logo
QR CodesAPIAutomations

Create QR codes with the API, MCP, and automations

Create, update, list, and delete QR codes with the CodeQR API, one by one or in bulk, from an AI client through the MCP server, or from Make and webhooks.

Avatar for undefined
CodeQR Team
Content Team

At the end of this guide you can create QR codes from your own system — one per order, table, product, or spreadsheet row — change where they point, list and delete them, and get notified of every scan, using the REST API, the MCP server, or Make.

Availability

  • Plan: the API is on all plans; the monthly QR code allowance is the same as in the app (Free 5, Starter 150, Pro 1,000 dynamic + unlimited static, Business 5,000). Requests per minute: Free 60, Starter 100, Pro 500, Business 1,000. Per-code scan webhooks need Business.
  • Where: https://api.codeqr.io/qrcodes with a key from SettingsAPI Keys; the MCP server at https://mcp.codeqr.io/mcp; the CodeQR app in Make. Full field reference: docs.codeqr.io.

Before you start

  • Create an API key in SettingsAPI KeysCreate, name it, choose the permissions, and copy the value once. Send it as Authorization: Bearer codeqr_….
  • type is the only required field. static defaults to false (dynamic). domain and key are optional; without them CodeQR uses the workspace domain and a random key ending in -qr. key cannot be reused within the workspace.
  • Design defaults through the API: size 1024, level M, black on white, showLogo true (workspace logo). Send "level": "H" when the code carries a logo — the editor does this for you, the API does not.

Endpoints

  • POST /qrcodes — What it does: Create one code
  • POST /qrcodes/bulk — What it does: Create 1 to 100 codes in one call (array body)
  • GET /qrcodes — What it does: List and filter (type, format=static · dynamic, search, tagIds, folderId, sort=createdAt · scans · lastClicked, page, pageSize up to 100, and more)
  • GET /qrcodes/count — What it does: Count with the same filters, optional groupBy
  • GET /qrcodes/info?domain=…&key=… — What it does: Retrieve one code by domain and key (there is no GET /qrcodes/{id})
  • PUT /qrcodes/{qrcodeId} — What it does: Update any field, including url, design, expiresAt, password, archived, and static: false to convert
  • DELETE /qrcodes/{qrcodeId} — What it does: Delete one code
  • DELETE /qrcodes/bulk?qrcodeIds=id1,id2 — What it does: Delete several (comma-separated ids in one parameter)
  • GET https://api.codeqr.io/qr?url=<shortLink> — What it does: PNG of an existing code (no key needed)

Steps: create codes from your data

  1. Create one code to check the fields you need:
curl -X POST https://api.codeqr.io/qrcodes \
  -H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "type": "url", "url": "https://example.com/menu", "title": "Cafe menu", "static": false }'

Response (200 OK, abbreviated): "id": "cmsx875y30001je433cy0ltlh", "key": "iVx0OCFyDn79-qr", "shortLink": "https://qrup.link/iVx0OCFyDn79-qr", "image": "https://res.cloudinary.com/dhnaggn4g/image/upload/v1786970667/qrup.link/iVx0OCFyDn79-qr.png", "scans": 0.

  1. Create many at once — one object per row, up to 100 per call. Add externalId with your own record id so you can find the code again:
curl -X POST https://api.codeqr.io/qrcodes/bulk \
  -H "Authorization: Bearer codeqr_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '[
    { "type": "url", "url": "https://example.com/table/1", "title": "Table 1", "static": false },
    { "type": "url", "url": "https://example.com/table/2", "title": "Table 2", "static": false }
  ]'

Response (200 OK, abbreviated): an array in the same order — "key": "XD2lytoBgPOe-qr" and "key": "IS87MRzr7Gos-qr", each with its shortLink. Bulk-created codes come back with "image": null; render them with https://api.codeqr.io/qr?url=<shortLink> or open them in the app.

  1. Store id, key, and shortLink next to your record. Print the image from image or from the /qr endpoint, or export SVG from the app.
  2. To change where a code goes, send PUT /qrcodes/{id} with { "url": "https://example.com/menu-v2" } — see Change a QR code destination after printing. To convert a static record, send { "static": false }.
  3. To find a code from its printed short link, call GET /qrcodes/info?domain=qrup.link&key=iVx0OCFyDn79-qr. To list, GET /qrcodes?type=wifi&pageSize=2 returns the two most recent Wi-Fi codes; GET /qrcodes/count returns the total (100 in the test workspace).
  4. To delete, DELETE /qrcodes/{id} returns { "id": "…" }; a scan of that code then answers 302 https://codeqr.io/not-found. DELETE /qrcodes/bulk?qrcodeIds=id1,id2 returns { "deletedCount": 2 } — pass the ids comma-separated in one parameter, not repeated.

Other fields you can send: expiresAt + expiredUrl, password, folderId, tagIds, comments, trackConversion (Pro), rules (Smart Rules, Business, dynamic only), preRedirection + pageId (Business), and the design fields (fgColor, bgColor, size, pattern, shape, frame, frameText, frameTextStyles, showLogo). Types other than url take their object: wifi, whatsapp, vcard, email, phone, text, pix (static only) — examples in Create WhatsApp, Wi-Fi, and vCard QR codes.

Errors you will meet

  • 422 — Message (verbatim): invalid_type: type: Required · Fix: Send type
  • 422 — Message (verbatim): custom: url: Invalid URL · Fix: Absolute https:// URL
  • 400 — Message (verbatim): Missing Wi-Fi SSID. / Missing PIX data. / Missing WhatsApp number. · Fix: Fill the type object
  • 400 — Message (verbatim): Invalid size. · Fix: size between 128 and 5000
  • 422 — Message (verbatim): invalid_string: whatsapp.number: Invalid WhatsApp number (use E.164 digits, e.g. 5511999999999) · Fix: Digits only, with country code
  • 422 — Message (verbatim): too_big: frameText: Frame text must be at most 200 characters · Fix: Shorten frameText
  • 403 — Message (verbatim): Smart rules can only be used on dynamic QR codes. · Fix: Drop rules or send static: false
  • 403 — Message (verbatim): You have reached the monthly limit of {N} qrcodes on the {Plan} plan. Please upgrade to add more QR Codes. · Fix: Wait for the next cycle, delete codes, or upgrade
  • 409 — Message (verbatim): Duplicate key: this qr code already exists. · Fix: Use another key or omit it

Every error body has error.code, error.message, and error.doc_url.

The same through the MCP server

Connect your AI client to https://mcp.codeqr.io/mcp (OAuth 2.0). Ask, for example:

Create a QR code for https://example.com/menu titled "Cafe menu".

The client calls create_qrcode with { "url": "https://example.com/menu", "title": "Cafe menu" } and gets the created object with key and shortLink. Available tools: create_qrcode (types url, text, email, phone, sms, wifi, vcard, crypto, whatsapp; plus domain, key, size, level, fgColor, bgColor), update_qrcode (qrcodeId + the same payload fields, archived), list_qrcodes (page), delete_qrcode. The MCP tools create dynamic codes only and do not take static, design patterns, frames, rules, tags, folders, expiresAt, or password — use the API for those.

Automations

  • Make: use the CodeQR app; the module Make an API Call sends any of the requests above (method POST, URL /qrcodes, body as shown), which is how you create one code per spreadsheet row. Make also receives the QR code events below.
  • Webhooks: in SettingsWebhooks, subscribe to qrcode.created, qrcode.updated, qrcode.deleted (workspace level) and, on Business, qrcode.scanned (chosen per code, with the scan's country, city, device, browser, and OS). Payloads: docs.codeqr.io.
  • Zapier: no QR code triggers or actions today (link and lead events only); use a webhook or HTTP request step with the API calls above.

Verify it works

curl -sI -A "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X)" \
  https://qrup.link/XD2lytoBgPOe-qr | grep -iE "^HTTP|^location"
# HTTP/2 302
# location: https://example.com/table/1

Then GET /qrcodes/info?domain=qrup.link&key=XD2lytoBgPOe-qr shows "scans": 1, and GET https://api.codeqr.io/analytics?event=clicks&groupBy=count&interval=24h&qrcodeId=cmsx899e5000hje43xlr42g24 returns {"clicks":0,"scans":1,"views":0,"leads":0,"sales":0,"saleAmount":0}. groupBy=top_qrcodes lists your codes with their scans.

Troubleshooting

The code I created through the API is static

static defaults to false, so codes are dynamic unless you send "static": true. Check the static field in the response.

GET /qrcodes/{id} returns 404

That route does not exist. Use GET /qrcodes/info?domain=…&key=… or GET /qrcodes?search=….

DELETE /qrcodes/bulk deleted only one code

Repeated qrcodeIds= parameters keep only one value. Send them comma-separated in a single qrcodeIds.

The API created a dynamic Pix code that opens the domain home page

Pix must be static: send "static": true with type: "pix".

DELETE /qrcodes/{id} returned 500

Check whether the code still exists with GET /qrcodes/info?domain=…&key=… before retrying: in our tests the code had been deleted even though the response was 500, and the retry answered 404 "qrCode not found.".

GET https://api.codeqr.io/qr?url=… returns 500

The url must be a CodeQR short link of an existing code (https://<domain>/<key>-qr); other URLs are not rendered.

Related articles