QR codes API & MCP

Generate QR images, create editable (dynamic) codes you can repoint anytime, and read scan stats — over a REST API or an MCP server for AI agents. Free, with a key tied to your account.

Get a free API key

Enter your email — we'll send a magic link. No password. Then come back to run live examples here.

Generate a QR image

Tweak the controls — the preview updates live, the code stays in sync, and you can run it against the real API.

curl -X POST https://openqr.uk/v1/qr \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data":"https://openqr.uk","format":"png","size":512,"dark":"#232E3A","light":"#FFFFFF"}' \
  --output qr.png

Live preview — exactly what the API returns.

GET/v1/qr

Render a QR image straight from query params. Returns the raw image (image/svg+xml or image/png) — not JSON.

# SVG (default), 512px, your saved theme's colours:
curl "https://openqr.uk/v1/qr?data=https://openqr.uk&format=svg&size=512&margin=4&theme=Brand" \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" -o qr.svg

# PNG with explicit colours:
curl "https://openqr.uk/v1/qr?data=https://openqr.uk&format=png&dark=%23232E3A&light=%23FFFFFF" \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" -o qr.png

POST/v1/qr

Same renderer from a JSON body — handy for longer payloads. Returns the raw image.

curl -X POST https://openqr.uk/v1/qr \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data":"https://openqr.uk","format":"png","size":1024,"margin":4,"dark":"#232E3A","light":"#FFFFFF"}' \
  -o qr.png
Image parameters (query string or JSON body)
dataText or URL to encode. Required, max 2000 characters.
format"svg" (default) or "png".
sizePixel size, 64–2048. Default 512.
marginQuiet-zone modules, 0–16. Default 4 (or the theme's margin).
dark / lightForeground / background colour as hex (e.g. #232E3A). Override the theme.
themeA saved theme id or name — sets the image colours and margin. Explicit dark/light/margin win.

Account

GET /v1/me returns the account that owns your key — a cheap way to verify a key works and read back the connected identity (e.g. for a Zapier connection label).

GET/v1/me

Return the account (id, email, name, created_at) that owns the calling key.

curl https://openqr.uk/v1/me -H "Authorization: Bearer oqr_YOUR_API_KEY"

# → { "id": "...", "email": "you@example.com", "name": "You", "created_at": "2026-01-01T00:00:00.000Z" }

Authentication

Every request needs your API key as a Bearer token. Create, name and rotate keys in your dashboard.

Authorization: Bearer oqr_YOUR_API_KEY

Dynamic codes

A dynamic code is a short URL on oqr.to you can repoint forever — the printed QR never changes. Create one, then update its destination or read its scans.

POST/v1/dynamic

Create a dynamic code.

curl -X POST https://openqr.uk/v1/dynamic \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"destination":"https://example.com","label":"Spring flyer"}'

# → { "id": "...", "slug": "Ab3xKp", "short_url": "https://oqr.to/Ab3xKp", ... }

GET/v1/dynamic

List your dynamic codes (newest first, ?limit= up to 500).

curl https://openqr.uk/v1/dynamic \
  -H "Authorization: Bearer oqr_YOUR_API_KEY"

# → { "codes": [ { "id": "...", "slug": "Ab3xKp", "short_url": "...", "destination": "...", "label": "...", "status": "active", "created_at": "..." } ] }

PATCH/v1/dynamic/{id}

Edit any field the dashboard can — send only what you want to change.

# repoint (printed QR keeps working), rename, set a custom short link, tag, and file it:
curl -X PATCH https://openqr.uk/v1/dynamic/{id} \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "https://example.com/new",
    "label": "Summer promo",
    "slug": "summer",
    "tags": ["promo", "2026"],
    "folder_id": "FOLDER_ID"
  }'

# slug → oqr.to/summer (3–48 letters, numbers or hyphens). folder_id: null to un-file.

POST/v1/dynamic/bulk

Create up to 200 dynamic codes in one request.

curl -X POST https://openqr.uk/v1/dynamic/bulk \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"codes":[
        {"destination":"https://example.com/a","label":"A"},
        {"destination":"https://example.com/b"}
      ]}'

# → { "created": [ { "id": "...", "slug": "...", "short_url": "...", ... } ] }

GET/v1/dynamic/{id}/scans

Scan summary + full analytics (daily series, country/device/referrer; ?days= up to 365).

curl "https://openqr.uk/v1/dynamic/{id}/scans?days=30" \
  -H "Authorization: Bearer oqr_YOUR_API_KEY"

# → {
#   "scans": { "total": 42, "last7": 9, "topCountry": "GB", "topDevice": "mobile" },
#   "analytics": {
#     "days_window": 30, "total": 42, "window_total": 31,
#     "daily": [ { "day": "2026-06-01", "n": 3 }, ... ],
#     "by_country": [ { "value": "GB", "n": 20 }, ... ],
#     "by_device":  [ { "value": "mobile", "n": 28 }, ... ],
#     "by_referrer":[ { "value": "instagram.com", "n": 12 }, ... ]
#   }
# }

DELETE/v1/dynamic/{id}

Delete a code.

curl -X DELETE https://openqr.uk/v1/dynamic/{id} \
  -H "Authorization: Bearer oqr_YOUR_API_KEY"

Folders

Organise codes into folders. Move a code with folder_id on PATCH /v1/dynamic/{id}. Deleting a folder un-files its codes — it never deletes them.

GET/v1/folders

List your folders.

curl https://openqr.uk/v1/folders -H "Authorization: Bearer oqr_YOUR_API_KEY"
# → { "folders": [ { "id": "...", "name": "Campaign" } ] }

POST/v1/folders

Create a folder.

curl -X POST https://openqr.uk/v1/folders \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Campaign"}'   # → { "id": "...", "name": "Campaign" }

PATCH/v1/folders/{id}

Rename a folder.

curl -X PATCH https://openqr.uk/v1/folders/{id} \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Q3 Campaign"}'

DELETE/v1/folders/{id}

Delete a folder (codes are un-filed).

curl -X DELETE https://openqr.uk/v1/folders/{id} \
  -H "Authorization: Bearer oqr_YOUR_API_KEY"

Themes

A theme is a saved style (colours, dot/corner shapes, logo, gradient, frame). Save one in the dashboard, then apply it anywhere by passing theme (its id or name) when creating, bulk-creating or editing a code. On /v1/qr a theme sets the image colours/margin; on dynamic codes the full style is stored for every download.

GET/v1/themes

List your saved themes (id, name, style).

curl https://openqr.uk/v1/themes -H "Authorization: Bearer oqr_YOUR_API_KEY"
# → { "themes": [ { "id": "...", "name": "Brand", "style": { ... } } ] }

POST/v1/themes

Save a reusable theme.

curl -X POST https://openqr.uk/v1/themes \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Brand","style":{"fgColor":"#07B1B0","bgColor":"#FFFFFF","dotType":"rounded"}}'

apply a theme

Pass theme (id or name) to any create/edit endpoint.

# new code styled with a theme:
curl -X POST https://openqr.uk/v1/dynamic \
  -H "Authorization: Bearer oqr_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"destination":"https://example.com","theme":"Brand"}'

# a QR image in the theme's colours:
curl "https://openqr.uk/v1/qr?data=https://example.com&theme=Brand&format=svg" \
  -H "Authorization: Bearer oqr_YOUR_API_KEY"

DELETE/v1/themes/{id}

Delete a theme (styled codes keep their look).

curl -X DELETE https://openqr.uk/v1/themes/{id} \
  -H "Authorization: Bearer oqr_YOUR_API_KEY"

Rate limits

Creating dynamic codes is capped at 20 per hour on a rolling window (this covers POST /v1/dynamic and each code in a POST /v1/dynamic/bulk batch). Reads, edits, deletes and QR-image rendering are not counted. Every create response carries your current budget in headers:

Rate-limit response headers
X-RateLimit-LimitMax creations per rolling hour (20).
X-RateLimit-RemainingCreations left in the current window.
X-RateLimit-ResetUnix seconds (UTC) when a slot frees up.

When you exceed the window the API returns 429 Too Many Requests with a Retry-After header (seconds to wait) alongside the same X-RateLimit-* headers:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1751299200
Retry-After: 1843

{ "error": "Too many codes created recently. Try again later." }

Errors

Every error response is JSON with a single error string and the matching HTTP status. Successful calls return 2xx (codes are created with 201); image endpoints return the raw image bytes rather than JSON.

{ "error": "Human-readable description of what went wrong." }
Status codes
400 Bad RequestA field is missing or invalid — e.g. a disallowed or private destination, a bad slug, malformed JSON, or `data` over 2000 characters.
401 UnauthorizedMissing, invalid or revoked Bearer key. Create or rotate keys in your dashboard.
404 Not FoundThe code, folder or theme doesn't exist, or isn't owned by your key.
429 Too Many RequestsDynamic-code creation rate limit hit — see the Rate limits section and Retry-After.
500 Internal Server ErrorUnexpected server-side failure. Safe to retry with backoff.

MCP server

Read the full MCP guide → — tools, supported clients, use cases and worked examples.

Point any MCP-capable agent (Claude, Cursor, …) at https://openqr.uk/mcp with your key. Anything you can do in the dashboard, an agent can do here. Tools: generate_qr, create_dynamic_qr, update_dynamic_qr (destination, label, slug, tags, folder, theme), get_scans, list_dynamic_qr, delete_dynamic_qr, bulk_create_dynamic_qr, list_folders, create_folder, delete_folder, list_themes, create_theme, delete_theme.

Connect your MCP client

Pick your client below, paste the config, and swap in your oqr_ key from this page (the key bar at the top). Endpoint is https://openqr.uk/mcp — Streamable HTTP, key in the Authorization header.

// claude_desktop_config.json — Settings → Developer → Edit Config.
// Claude Desktop speaks stdio, so bridge to the remote server with mcp-remote.
{
  "mcpServers": {
    "openqr": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://openqr.uk/mcp",
        "--header", "Authorization: Bearer oqr_YOUR_API_KEY"
      ]
    }
  }
}
// Restart Claude Desktop, then ask it to "generate a QR code for openqr.uk".

Every tool — including generate_qr — needs a key, since codes are tied to your account. Create a free one in seconds at the top of this page.

Keep learning

Free with generous rate limits. Keys are tied to your account so we can keep abuse off the network — the tool itself stays free and no-signup.

Stay on top of the API

Get the changelog and new endpoints in your inbox — occasional, developer-focused, no spam.

Double opt-in — we'll email you to confirm. No spam, unsubscribe anytime. See our privacy policy.