Download every QR code of a campaign as one ZIP
method
GET
host
strait.
version
/v1
resource
/
GET /v1/qr.zip
Auth: secret key as Authorization: Bearer. Server-side only.
Request
A ZIP with one QR code per live link whose campaign is campaign (case-insensitive, the same match as the dashboard's links filter), named <slug>-qr.<format> and sorted by slug. Same style rules as GET /v1/links/{slug}/qr: the workspace default or preset, overridden by color / background / logo, refused (400) when it would not scan. SVG by default (vector, for print). At most 500 codes as SVG, or 50 as PNG at up to 1024 px. Rate limit: 3 ZIPs a minute per workspace; one PNG ZIP at a time server-wide.
Parameters
campaignrequired string query- The links' campaign name, e.g.
diwali_sale format"svg" | "png" query- Image format of every code
sizeinteger query- Width and height in pixels (PNG: at most 1024)
margininteger query- Quiet zone around each code, in modules
presetstring query- A saved QR style id (Settings → QR codes)
colorstring query- Code colour as hex, overrides the style
backgroundstring query- Background colour as hex, overrides the style
logoboolean query- Put the app icon in the middle, overrides the style
trackboolean query- Add utm_source=qr so scans count as the qr channel
tenantIdstring query- Dashboard sessions only: the workspace id
Response
- 200 The ZIP (stored, not compressed)
- 400 No campaign, unknown preset, colours that would not scan, PNG over 1024 px, or more links than the ZIP holds
- 401 Missing or invalid secret key / session
- 404 No live links in this campaign
- 429 More than 3 ZIPs a minute for this workspace, or another PNG ZIP is being made
- 503 PNG rendering stayed busy for 30 s; retry or use SVG
curl -X GET "https://strait.link/v1/qr.zip?campaign=value" \
-H "Authorization: Bearer $SECRET_KEY"const res = await fetch('https://strait.link/v1/qr.zip?campaign=value', {
headers: { Authorization: `Bearer ${process.env.SECRET_KEY}` },
});
const text = await res.text();
console.log(res.status, text);import os
import requests
res = requests.get(
"https://strait.link/v1/qr.zip?campaign=value",
headers={"Authorization": f"Bearer {os.environ['SECRET_KEY']}"},
)
print(res.status_code, res.text)<?php
// Plain PHP with ext-curl, no packages. In Laravel, Http::withToken($secretKey)->get($url) sends the same request.
$ch = curl_init('https://strait.link/v1/qr.zip?campaign=value');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SECRET_KEY'),
],
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
echo $status, PHP_EOL, $response, PHP_EOL;import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
// Java 17+, java.net.http only (no dependencies).
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://strait.link/v1/qr.zip?campaign=value"))
.header("Authorization", "Bearer " + System.getenv("SECRET_KEY"))
.GET()
.build();
HttpResponse<String> res = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(res.statusCode() + " " + res.body());
}
}package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://strait.link/v1/qr.zip?campaign=value", nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("SECRET_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
data, err := io.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(res.StatusCode, string(data))
}The response, printed
HTTP/1.1 200 OK