The QRFLOW.codes API

REST · JSON · API keys on Business

Everything the dashboard does, from your own code: create codes, change where a dynamic code points without reprinting, name links on your domain, pull scan numbers, bulk-generate. The same endpoints serve the QRFLOW app for Canva.

Get a key
  1. On the Business plan ($29 a month), open Account › API keys.
  2. Name the key and pick its scopes: codes:read, codes:write, analytics:read, domains:read.
  3. Copy it once; it looks like qrf_live_…. Send it as Authorization: Bearer on every request.

Keys are for servers. Never put one in a web page, a mobile app or a shared spreadsheet; revoke and re-issue if one leaks. 600 requests a minute per key; up to 10 keys per account.

export QRFLOW_KEY=qrf_live_…
curl https://qrflow.codes/api/v1/me -H "Authorization: Bearer $QRFLOW_KEY"

Endpoints

Base URL https://qrflow.codes/api/v1. Bodies and responses are JSON. Dates are ISO 8601 in UTC.

GET/meprofile

Who the key belongs to

Plan, feature flags and the limits that apply to this account, plus the key's scopes.

curl https://qrflow.codes/api/v1/me \
  -H "Authorization: Bearer $QRFLOW_KEY"
{ "id": "…", "email": "ops@acme.com", "plan": "business", "paid": true,
  "features": { "dynamic_codes": true, "custom_domain": true, "link_names": true, "gs1": true, "api_keys": true },
  "limits": { "saved_codes": 25000, "bulk_per_month": 10000, "bulk_per_request": 2000, "link_domains": 5, "requests_per_minute": 600 },
  "auth": "api_key", "scopes": ["codes:read", "codes:write"] }

GET/catalogpublic

Every kind of code

Native types (url, wifi, vcard, email, phone, sms, text, location) and the 50-odd subtypes (Instagram, Google review, Wi-Fi, app store…), each with the fields it needs and the plan it requires. No key needed.

curl https://qrflow.codes/api/v1/catalog

GET/codescodes:read

List codes

Newest first. ?limit= up to 100, ?q= searches labels.

curl "https://qrflow.codes/api/v1/codes?limit=20&q=menu" \
  -H "Authorization: Bearer $QRFLOW_KEY"

POST/codescodes:write

Create a code

Same rules as Save on the site: url, phone, email, sms and location codes are dynamic on paid plans; Wi-Fi, vCard and text carry their content in the pattern. Put a subtype id in destination_data.subtype to make, say, a Google review code.

curl -X POST https://qrflow.codes/api/v1/codes \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "url", "destination_data": { "url": "https://acme.com/menu" }, "label": "Table tents", "frame_style": "caption-below", "frame_caption": "Scan for menu" }'
{ "code": { "id": "…", "label": "Table tents", "kind": "url", "dynamic": true, "short_code": "x7k2p9a",
  "short_url": "https://go.acme.com/x7k2p9a", "scans": 0, "image_url": "https://qrflow.codes/api/v1/codes/…/image.svg", … } }

GET/codes/:idcodes:read

One code

The code with its scan count, short link and image address.

curl https://qrflow.codes/api/v1/codes/$ID \
  -H "Authorization: Bearer $QRFLOW_KEY"

PATCH/codes/:idcodes:write

Change a code

Any of: destination_data (dynamic codes only, the print stays valid), label, paused, expires_at (ISO or null), slug (a link name on your domain), fg_color, bg_color, frame_style, frame_caption, frame_caption2. Send only the fields you are changing.

curl -X PATCH https://qrflow.codes/api/v1/codes/$ID \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "destination_data": { "url": "https://acme.com/menu-fall" }, "slug": "menu" }'

DELETE/codes/:idcodes:write

Delete a code

Gone for good, including its scan history. A dynamic code's printed link stops resolving. Prefer paused: true if the print is still out there.

curl -X DELETE https://qrflow.codes/api/v1/codes/$ID \
  -H "Authorization: Bearer $QRFLOW_KEY"
204 No Content

POST/codes/:id/dynamiccodes:write

Make a static code dynamic

The printed pattern changes (it now encodes the short link), so re-render the image afterwards.

curl -X POST https://qrflow.codes/api/v1/codes/$ID/dynamic \
  -H "Authorization: Bearer $QRFLOW_KEY"

GET/codes/:id/image.svgcodes:read

The image

Print-ready SVG with the frame and colors. ?size= sets the module grid width in px; the file scales without loss anyway.

curl https://qrflow.codes/api/v1/codes/$ID/image.svg \
  -H "Authorization: Bearer $QRFLOW_KEY" -o code.svg

GET/codes/:id/scansanalytics:read

Scan analytics

?from= and ?to= (ISO dates, up to 92 days, default the last 30) and ?group= day, device, country, city, browser, os or referrer. The same numbers as the analytics page.

curl "https://qrflow.codes/api/v1/codes/$ID/scans?from=2026-09-01&to=2026-09-21&group=day" \
  -H "Authorization: Bearer $QRFLOW_KEY"
{ "code_id": "…", "from": "…", "to": "…", "group": "day", "total": 412,
  "rows": [ { "key": "2026-09-01", "scans": 18 }, { "key": "2026-09-02", "scans": 25 }, … ] }

POST/codes/bulkcodes:write

Bulk create

Up to 2,000 URL codes in one call, all dynamic. Counts against the same monthly bulk allowance as the Bulk page (10,000 on Business). Rows that are not web addresses come back in rejected; the rest are created.

curl -X POST https://qrflow.codes/api/v1/codes/bulk \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "rows": [ { "destination": "https://acme.com/t/1", "label": "Table 1" }, { "destination": "https://acme.com/t/2", "label": "Table 2" } ] }'
{ "codes": [ … ], "rejected": [], "remaining_this_month": 9998 }

GET/domainsdomains:read

Link domains

Your connected domains, their status, and which one dynamic codes print with (default_base).

curl https://qrflow.codes/api/v1/domains \
  -H "Authorization: Bearer $QRFLOW_KEY"

GET/framespublic

Frames

Frame ids and what each needs (caption, second line), grouped like the customizer. No key needed.

curl https://qrflow.codes/api/v1/frames

Errors

Every error is { "error": "<code>", "message": "<what to do>" } with the status below.

StatuserrorMeaning
400invalid_request · invalid_destination · not_dynamic · no_domain · bulk_limitSomething in the request; the message says what.
401invalid_tokenMissing, revoked or unknown key.
402upgrade_requiredThe account's plan does not include this (or the key's plan ended).
403insufficient_scopeThe key was not created with that scope.
404not_foundNo such code in this account.
409conflictThe link name is already used by another code.
429rate_limitedOver 600 requests in a minute; Retry-After says how long.

Good to know

  • Codes created by a key show up in the dashboard with the key's name as their source, so you can tell your integration's codes from hand-made ones.
  • A dynamic code's short_url is what to print. It uses your default link domain when one is connected, otherwise qrflow.codes/q/….
  • Changing destination_data on a dynamic code never changes the printed pattern. Changing slug does change the link, so set names before printing.
  • Scan analytics count what the redirect saw: device, country and city come from the request, never from cookies or ids.
  • If the account leaves Business, keys keep working for 30 days, then answer 402. Nothing is deleted.
  • Webhooks (scan events pushed to your URL) are not available yet; poll /codes/:id/scans for now. Questions: hello@qrflow.codes.