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