API documentation
Create QR codes programmatically. Generate an API key from your dashboard first — the raw key is shown once at creation time, so save it somewhere safe. Want an AI tool to do this for you instead of writing requests by hand? See the MCP server.
Authentication
Every request must include your API key as a Bearer token in the Authorization header:
Authorization: Bearer qrd_live_<your key>A missing or malformed header returns 401. An unknown or revoked key also returns 401 with { "error": "Invalid or revoked API key" }.
API access itself requires the $30/mo plan or higher — a valid, non-revoked key belonging to a Free or $10/mo account still gets 403:
{ "error": "API access requires the $30/mo plan or higher" }Rate limits
Rate limit depends on your plan: 60 requests/minute on $30/mo, 300 requests/minute on $50/mo. Exceeding it returns 429 with a Retry-After header (seconds) and:
{ "error": "Rate limit exceeded: max 60 requests per 60s" }POST /api/v1/qr
Creates a QR code. Body fields:
| Field | Type | Required | Notes |
|---|---|---|---|
type | "url" | "wifi" | "vcard" | yes | Which payload shape to encode. |
dynamic | boolean | no | Defaults to true. Dynamic codes redirect through /q/<code>, track scans, and count against your plan's dynamic QR limit. Static codes encode the payload directly and aren't tracked or limited. |
payload | object | yes | Shape depends on type — see examples below. |
style | object | no | { foregroundColor?, backgroundColor?, logoDataUrl? } — hex colors and/or a base64 data: URL logo. Requires the $10/mo plan or higher; a logo automatically raises error correction to High so the code still scans. |
alias | string | no | Custom short code for a dynamic QR code instead of a random one. Must be unique. |
label | string | no | Name shown in the dashboard, up to 80 characters. |
expiresAt | string | no | ISO date string after which a dynamic code stops resolving. |
If your account has an active custom domain, dynamic codes created here encode that domain instead of the shared app domain.
Example: dynamic URL QR code
curl -X POST https://your-domain.example/api/v1/qr \
-H "Authorization: Bearer qrd_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "url",
"dynamic": true,
"payload": { "destination": "https://example.com" }
}'Example: static WiFi QR code
curl -X POST https://your-domain.example/api/v1/qr \
-H "Authorization: Bearer qrd_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "wifi",
"dynamic": false,
"payload": { "ssid": "CoffeeShop", "password": "brew1234", "security": "WPA3", "hidden": false }
}'Success response — 200
The generated PNG is returned inline as a base64 data URL, so there's no separate image-fetch round trip. Dynamic codes also include the record id and shortCode:
{
"id": "6f2c9a3e-...-c9ab",
"shortCode": "aB3xY9",
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}Error responses
400— invalid payload for the giventype.401— missing/malformed/invalid/revoked API key.403— API access requires $30/mo+, custom styling requires $10/mo+, or your plan's dynamic QR code limit is reached.409— the requestedaliasis already taken.429— rate limit exceeded for this key.
Other endpoints
All authenticated the same way as above, and subject to the same rate limit.
| Endpoint | What it does |
|---|---|
GET /api/v1/qr | Lists every QR code owned by the key's account. |
GET /api/v1/qr/<id> | Fetches one QR code by id. |
PATCH /api/v1/qr/<id> | Edits a dynamic code's payload, label, expiresAt, or password — only fields you include are changed. Static codes can't be edited. |
DELETE /api/v1/qr/<id> | Deletes a QR code. Its short URL stops resolving immediately. |
POST /api/v1/qr/bulk | Creates many codes at once from CSV text in the csv field, with an optional shared style. Requires the $30/mo plan or higher. Max 500 data rows per request. |