REST API · OpenAPI 3.1 · MCP

The QR code API for codes that outlive the print run

Create a code from your own code, print the short link it returns, and change where it goes months later without reprinting anything. Every scan is counted, webhooks tell your systems, and the whole thing is a dozen endpoints over HTTPS.

create a dynamic 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://example.com/menu" } }'

Read this first

You might not need this API

Most searches for a QR code API are looking for something simpler than this, and sending you to the wrong tool would waste your afternoon. Here is the honest fork.

You want an image of a string

Use a library, not a service: qrcode on npm, qrcode in Python, or the equivalent in your language. It renders offline, costs nothing, has no rate limit and cannot be turned off. For a one-off by hand, our free generator does it in the browser.

You want a generator on your site

Two lines of HTML and no key: the embeddable generator puts a working QR code maker on any page, and your visitors download from their own browser.

You want codes you still control

Destinations you can change after printing, scan analytics, your own domain, webhooks, bulk runs. That is this API, and it is the part a library cannot do, because it needs something alive at the other end of the link.

What you get

Change the destination after printing

PATCH a code and every printed copy follows within a second. The pattern never changes, which is the whole reason this is a service and not a library.

Every scan, grouped

Counts by day, device, country and city, in windows up to 92 days, as JSON you can chart or push into your own warehouse.

Your own domain

Codes print as go.yourbrand.com/x7k2p9a instead of ours, and Business accounts can connect up to 5 of them with readable link names.

Webhooks

Signed deliveries when a code is scanned, created or changed, with retries over 12 hours and a stable event id so you can make handling idempotent.

Bulk

Up to 2,000 codes in one request and 10,000 a month, for one code per table, per asset, per attendee or per SKU.

An MCP server too

The same account, reachable from Claude, ChatGPT, Cursor and Claude Code through sign-in, so a person can ask for a code in words while your server uses the key.

A working integration, start to finish

Create the code, print short_url, change the destination when the season changes, read the scans. That is the entire lifecycle, in every language we ship a client for.

curl
export QRFLOW_KEY=qrf_live_...   # from Account › API keys

# 1. Who am I, what can this key do?
curl https://qrflow.codes/api/v1/me -H "Authorization: Bearer $QRFLOW_KEY"

# 2. Make a dynamic code. Print what comes back as short_url.
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://example.com/menu" }, "label": "Table tents" }'

# 3. The print-ready image (SVG, with your colors and frame).
curl "https://qrflow.codes/api/v1/codes/$CODE_ID/image.svg?size=1024" \
  -H "Authorization: Bearer $QRFLOW_KEY" -o menu.svg

# 4. Fall menu. The printed code keeps working.
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID \
  -H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
  -d '{ "destination_data": { "url": "https://example.com/menu-fall" } }'

# 5. How did it do?
curl "https://qrflow.codes/api/v1/codes/$CODE_ID/scans?group=day" -H "Authorization: Bearer $QRFLOW_KEY"
TypeScript (Node 18+, Bun, Deno, Workers)
// npm install qrflow   (zero dependencies; ESM + CommonJS; full types)
import { QRFlow, QRFlowError } from "qrflow";

const qr = new QRFlow(process.env.QRFLOW_KEY!);

const { code } = await qr.createCode({
  type: "url",
  destination_data: { url: "https://example.com/menu" },
  label: "Table tents",
});
console.log(code.id, code.short_url);        // save both; print short_url

await qr.updateCode(code.id, { destination_data: { url: "https://example.com/menu-fall" } });

const stats = await qr.scans(code.id, { group: "day" });
console.log(stats.total, stats.rows);         // [{ key: "2026-09-21", scans: 18 }, ...]

try {
  await qr.updateCode(code.id, { slug: "menu" });
} catch (e) {
  if (e instanceof QRFlowError) console.log(e.status, e.code, e.message); // 400 no_domain: connect a domain first
}
Python 3.9+ (standard library only)
# Download https://qrflow.codes/sdk/qrflow.py next to your code.
import os
from qrflow import QRFlow, QRFlowError

qr = QRFlow(os.environ["QRFLOW_KEY"])

code = qr.create_code(type="url", destination_data={"url": "https://example.com/menu"}, label="Table tents")["code"]
print(code["id"], code["short_url"])          # save both; print short_url

qr.update_code(code["id"], destination_data={"url": "https://example.com/menu-fall"})

stats = qr.scans(code["id"], group="day")
print(stats["total"], stats["rows"])

try:
    qr.update_code(code["id"], slug="menu")
except QRFlowError as e:
    print(e.status, e.code, e)                # 400 no_domain: connect a domain first

The endpoints

Twelve of them, plus webhooks. Bearer token, JSON in, JSON out, ordinary HTTP status codes. The full reference has request and response bodies for each, and there is an OpenAPI 3.1 document if you would rather generate a client.

MethodPathWhat it does
GET/meWho the key belongs to
GET/catalogEvery kind of code
GET/codesList codes
POST/codesCreate a code
GET/codes/:idOne code
PATCH/codes/:idChange a code
DELETE/codes/:idDelete a code
POST/codes/:id/dynamicMake a static code dynamic
GET/codes/:id/image.svgThe image
GET/codes/:id/scansScan analytics
POST/codes/bulkBulk create
GET/domainsLink domains
GET/webhooksList webhooks
POST/webhooksCreate a webhook
POST/webhooks/:idTest a webhook
DELETE/webhooks/:idRemove a webhook
GET/framesFrames

Migrating

Replacing Google's old chart API

For years the quickest QR code in any codebase was a chart.googleapis.com image URL. It was deprecated long ago and now returns 404 for QR requests, which we checked again in September 2026; the documentation page it lived on redirects to Google Charts, the JavaScript library, and that library does not draw QR codes at all.

If you only used it to render a picture, replace it with a library in your own code rather than another hosted image URL. The lesson of the original endpoint is that a free image service you do not control is a dependency that can disappear between one deploy and the next, and every printed code that pointed at it goes with it.

If what you actually liked was that the destination lived somewhere you could change, this API is the replacement worth the money: the image is yours to render however you like, and what we host is the redirect, the analytics and the promise that the printed code keeps working.

What it costs: $29 a month

API keys are part of Business, $29 a month, alongside 5 team seats, 5 link domains, GS1 Digital Link codes and the higher limits. There is no metered pricing and no per-code charge: 600 requests a minute per key, ten keys, ten webhooks, and fair-use caps you are unlikely to meet.

Codes made through the API behave exactly like codes made in the dashboard, so your team can pick one up and edit it by hand, and anything they make is visible to your key. Leaving Business does not delete anything: keys answer 402 after 30 days, and the codes themselves keep redirecting.

Full plan comparison · How to create a key

At a glance

Rate limit
600 req/min per key
Keys
10 per account
Webhooks
10 per account
Bulk
2,000 per request
Saved codes
25,000 (fair use)
Analytics window
92 days per request

Questions developers ask

Is there a free QR code API?
Not here, and it is worth being straight about it: our API is part of Business at $29 a month, because what it creates is a code we host and redirect for as long as it is printed. If all you need is an image of a string, you do not need an API at all. A library in your own code (qrcode on npm, qrcode in Python, or the same in any language) renders one offline, forever, for nothing.
What does the API do that a QR code library cannot?
A library draws a picture of whatever string you hand it, and that string is fixed the moment it is printed. This API creates a code whose destination lives on our side: you change where it points after it is on a thousand boxes, you see every scan by day, device and city, you print it on your own domain, and you get a webhook when something happens. If none of that matters, use the library.
Do I need an API key to use it from Claude or ChatGPT?
No, and this is the one part that is not Business-only. The MCP server at https://qrflow.codes/mcp authenticates with a normal sign-in, so an assistant can create and edit codes on any plan, including Free, within that plan's limits. API keys are the server-to-server route and stay on Business.
Where did Google's chart.googleapis.com QR endpoint go?
It is gone. The Image Charts endpoint was deprecated years ago and now answers 404 for QR requests (we checked in September 2026), and Google Charts, the JavaScript library that replaced it, does not draw QR codes at all. If you were using it for a plain image, a local library is the honest replacement. If the reason you wanted a hosted endpoint was that the destination might change, that is what this API is for.
What are the rate limits?
600 requests a minute per key. Past that you get a 429 with a Retry-After header, which the official clients respect. Ten keys and ten webhooks per account, 25,000 saved codes under fair use, and scan analytics in windows of up to 92 days.
Can I call it from the browser?
No, on purpose. The API refuses browser origins, because a key in front-end code is a key anyone can read and use to repoint your printed codes. Call it from your server, your worker or your build step, and keep the key in an environment variable.
Which languages are supported?
There is an official TypeScript client on npm (npm install qrflow, zero dependencies, ESM and CommonJS) and a single-file Python client. Everything else is plain REST over HTTPS with JSON, described by an OpenAPI 3.1 document you can point a generator at.
What happens to my codes if I stop paying?
Nothing is deleted. Keys and webhooks keep working for 30 days after you leave Business, then answer 402; codes already created keep redirecting, and the scan counter keeps running. Printed codes do not die because of a billing change.
Start reading, not signing up

The whole API fits in one page

Endpoints, schemas, webhook payloads, error codes, build recipes and prompts to paste into your assistant.