Developer Docs

Scanely QR Code API

Create, update, and track dynamic QR codes over REST. Every code you create through the API gets a trackable short URL whose destination you can change at any time — without reprinting anything. API access is included in the Business plan and Lifetime Business.

Authentication

Create an API key in Dashboard → Settings → API Keys, then pass it as a Bearer token. Keys inherit your account's plan limits.

curl https://scanely.io/api/qr \
  -H "Authorization: Bearer sk_live_your_key_here"

Quickstart — create your first code

curl -X POST https://scanely.io/api/qr \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "destinationUrl": "https://example.com/menu", "name": "Table 4" }'

The response contains a shortUrl — encode that into your printed QR code. Render the image with any library, or use the free generator.

Endpoints

POST/api/qr

Create a QR code

Request body

{
  "destinationUrl": "https://example.com/menu",  // required, http/https, ≤2048 chars
  "name": "Table 4",                             // optional, ≤255 chars
  "campaignTag": "menu_q3"                       // optional, ≤100 chars
}

Response

{
  "id": "3f8c9a2e-…",
  "slug": "Ab3xY9k",
  "shortUrl": "https://scanely.io/r/Ab3xY9k"
}
GET/api/qr

List your QR codes

Response

[
  { "id": "…", "slug": "…", "name": "…", "destination_url": "…", "campaign_tag": "…", "created_at": "…" }
]
PUT/api/qr/:id

Update a QR code

Request body

{
  "destinationUrl": "https://example.com/new-menu",  // any subset of fields
  "name": "Table 4 — patio",
  "campaignTag": "menu_q4",
  "isActive": true,
  "expiresAt": "2026-12-31T23:59:59Z"
}

Response

{ "success": true }
DELETE/api/qr/:id

Delete a QR code

Response

{ "success": true }
POST/api/qr/bulk

Bulk create (up to 1,000 per request)

Request body

{
  "items": [
    { "destinationUrl": "https://example.com/t1", "name": "Table 1", "campaignTag": "menu" },
    { "destinationUrl": "https://example.com/t2", "name": "Table 2", "campaignTag": "menu" }
  ]
}

Response

{
  "created": [ { "row": 1, "id": "…", "slug": "…", "shortUrl": "…" } ],
  "skipped": [ { "row": 7, "reason": "Invalid URL format" } ],
  "total": 2
}
GET/api/scans/:qrId?period=30d

Scan analytics for one code

Response

{
  "totalScans": 412,
  "timeSeries": [ { "date": "2026-06-01", "count": 18 } ],
  "geoBreakdown": [ { "country": "PL", "city": "Krakow", "count": 122 } ],
  "deviceBreakdown": [ { "device_type": "mobile", "count": 371 } ],
  "browserBreakdown": [ { "browser": "Safari", "count": 204 } ]
}

Errors and limits

  • 400 — validation failed; the message field says which input and why.
  • 401 — missing or invalid API key.
  • 403 — plan limit reached (QR code capacity or feature gate).
  • 404 — resource not found or owned by another account.
  • Bulk requests are capped at 1,000 items; each item is validated independently and skipped rows return a per-row reason.
  • All timestamps are ISO 8601 in UTC.

Ready to integrate?

API access ships with Business ($79/mo) and Lifetime Business ($149 one-time).