Authentication
Every request must include an Authorization: Bearer <key> header. Generate a key from the dashboard — it's a 51-character string starting with qr_.
API access is included on the Advanced ($10/mo) and Premium ($20/mo) plans. Free and Regular accounts can create a key but every request returns 403 api_not_available.
Rate limits & quotas
| Plan | Monthly requests | Notes |
|---|---|---|
| Free | — | API access not available |
| Regular | — | API access not available |
| Advanced | 3,000 / month | Resets on the 1st of every month (UTC) |
| Premium | 30,000 / month | Resets on the 1st of every month (UTC) |
If you exceed the quota, the API returns 429 quota_exceeded until the next reset. There is no per-second rate limit beyond the monthly cap.
Create a QR POST
POST /api/v1/qr
Creates a dynamic URL QR code. The server generates a unique short_code and returns the canonical scan URL. Counts against your dynamic-QR plan limit (Advanced: 200, Premium: unlimited).
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
label | string | yes | Internal name (e.g. "Fall campaign 2026") |
target_url | string (URL) | yes | Where the QR redirects when scanned |
qr_type | string | no | Always "url" for v1. Pro types (Menu, Landing, etc.) only via the dashboard for now |
fg_color | string | no | #RRGGBB hex, default #000000 |
bg_color | string | no | #RRGGBB hex, default #FFFFFF |
Example
curl -X POST https://qrlogo.org/api/v1/qr \
-H "Authorization: Bearer qr_" \
-H "Content-Type: application/json" \
-d '{
"label": "Restaurant menu — fall 2026",
"target_url": "https://example.com/menu",
"fg_color": "#1d4ed8",
"bg_color": "#ffffff"
}'
Response (201 Created)
{
"id": 42,
"short_code": "kpnh7vy",
"label": "Restaurant menu — fall 2026",
"qr_type": "url",
"target_url": "https://example.com/menu",
"scan_url": "https://qrlogo.org/r.php?c=kpnh7vy",
"scan_count": 0,
"fg_color": "#1d4ed8",
"bg_color": "#ffffff",
"created_at": "2026-04-07 14:30:12",
"updated_at": "2026-04-07 14:30:12"
}
The scan_url is what you encode into the printed QR code. Every scan of that URL goes through /r.php and gets logged.
List QR codes GET
GET /api/v1/qr
Returns up to 200 of the authenticated user's QR codes, newest first. Each row includes the current scan count.
Example
curl https://qrlogo.org/api/v1/qr \
-H "Authorization: Bearer qr_"
Response (200 OK)
{
"count": 2,
"qrs": [
{ "id": 42, "short_code": "kpnh7vy", "label": "...", "scan_count": 17, ... },
{ "id": 41, "short_code": "9bjkmqt", "label": "...", "scan_count": 4, ... }
]
}
Fetch one QR code GET
GET /api/v1/qr/{short_code}
Returns a single QR code with its current scan count. Returns 404 not_found if the short_code doesn't belong to the authenticated user.
Example
curl https://qrlogo.org/api/v1/qr/kpnh7vy \
-H "Authorization: Bearer qr_"
Error responses
Errors are JSON with the shape {"error": "code", "message": "human-readable text"}.
| HTTP | error | When |
|---|---|---|
| 400 | missing_label | POST without a label |
| 400 | invalid_url | target_url isn't a valid URL |
| 400 | invalid_type | Unknown qr_type |
| 400 | unsupported_type | You sent a non-url type via the v1 API (use the dashboard for Pro types) |
| 401 | missing_or_invalid_token | No Authorization header or wrong format |
| 401 | invalid_token | Bearer token doesn't match any user |
| 402 | quota_dynamic_qrs | You hit your plan's dynamic-QR cap (Advanced: 200) |
| 403 | api_not_available | Your plan (Free / Regular) doesn't include API access |
| 404 | not_found | The short_code doesn't belong to you |
| 405 | method_not_allowed | Wrong HTTP verb on this resource |
| 429 | quota_exceeded | You hit your monthly request quota |
Ready to start?
Sign up, upgrade to Advanced or Premium, generate an API key from the dashboard, and you're good to go.
Create account See pricing