API: the guide

Everything you need to create and manage QR codes from your software: authentication, copy-ready examples and limits. The full reference for every endpoint is in the interactive documentation.

Getting started

01

A plan with the API

API access is included in the plans listed on the feature page. You also need an account with a confirmed email.

02

Create a key

In Settings → API, name the key and copy it right away: we show it only once, then keep just a fingerprint.

03

Call the API

Send the key in the Authorization header of every request. Responses are JSON, except images.

Authentication and limits

Every request to /api/v1/qrcodes carries the key as a Bearer token. The key starts with ogqr_ followed by 64 hex characters; website session tokens are not accepted.

Authorization: Bearer $QRCODENOW_API_KEY
  • Base URL: https://dev.qrcodenow.ai/api/v1.
  • Each key can make 60 requests per minute. Beyond that we reply 429 with Retry-After: 60.
  • You can have up to 10 active keys and revoke them at any time from the settings; a revoked key stops working immediately.
  • A key acts as your account: it sees your QR codes and those shared with you, with the same role (editors can edit, only the owner can delete).
  • If your plan no longer includes the API or the account is deactivated, keys reply 401.

Create a dynamic QR code

A dynamic QR code points to our redirect address, so the destination can change after printing. For a link, type 2 with target_url is enough.

curl -X POST https://dev.qrcodenow.ai/api/v1/qrcodes \
  -H "Authorization: Bearer $QRCODENOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"idtype": 2, "title": "Volantino autunno", "target_url": "https://example.com/autunno"}'

201 response (shortened)

{
  "success": 1,
  "data": {
    "id": 128,
    "code": "k3x9q2m7ab",
    "idtype": 2,
    "is_dynamic": 1,
    "is_paused": 0,
    "title": "Volantino autunno",
    "target_url": "https://example.com/autunno",
    "qr_image_url": "https://…/i/k3x9q2m7ab.png",
    "scan_count": 0,
    "my_role": "owner"
  }
}

Keep id for later calls and code for the image. The QR code takes a slot in your plan quota, just like one created from the dashboard: when the quota is full the response is 403 with code: plan_qr_limit.

Types that encode the content in the QR code itself (vCard, WiFi, email…) read their fields from qr_payload, without target_url:

{
  "idtype": 4,
  "title": "Biglietto da visita",
  "qr_payload": {
    "firstname": "Giulia",
    "lastname": "Bianchi",
    "phone": "+39 333 1234567",
    "email": "giulia@example.com"
  }
}

List QR codes

The list is paginated: p is the page (from 1), c the items per page (100 max), srt the sort field (date_create, date_update, title, scan_count), o the direction (ASC or DESC) and s a search on title and code.

curl "https://dev.qrcodenow.ai/api/v1/qrcodes?p=1&c=50&srt=scan_count&o=DESC" \
  -H "Authorization: Bearer $QRCODENOW_API_KEY"

The response contains rows, total (all results), count (those on this page) and page. A single QR code is GET /api/v1/qrcodes/{id}.

Change the destination

With PATCH you change title and target_url. The printed code stays the same: whoever scans it lands on the new destination right away. You need at least the editor role on the QR code.

curl -X PATCH https://dev.qrcodenow.ai/api/v1/qrcodes/128 \
  -H "Authorization: Bearer $QRCODENOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target_url": "https://example.com/inverno"}'

Download the image

Every QR code has a public PNG image at qr_image_url; change the extension to .svg for the print-ready vector. No key needed. Add ?download=1 to download it as a file.

curl -o qr.svg "https://…/i/k3x9q2m7ab.svg?download=1"

Static QR code on the fly

To encode text without saving it to your account use POST /api/v1/qrcodes/static: it replies with the PNG directly and uses no quota. The text can be up to 1273 bytes long.

curl -X POST https://dev.qrcodenow.ai/api/v1/qrcodes/static \
  -H "Authorization: Bearer $QRCODENOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Testo da codificare"}' \
  -o static-qr.png

Delete a QR code

Only the owner can delete a QR code. The response is 204 with no body; from then on the printed code no longer redirects.

curl -X DELETE https://dev.qrcodenow.ai/api/v1/qrcodes/128 \
  -H "Authorization: Bearer $QRCODENOW_API_KEY"

QR code types (idtype)

Dynamic types require target_url. The others are direct: the content lives inside the QR code and goes in qr_payload.

idtype Type Mode Fields
1 App store (iOS, Android, desktop) Dynamic target_url, url_ios, url_android, url_desktop
2 Website link Dynamic target_url
3 Digital menu Dynamic target_url
4 Business card (vCard) Direct firstname, lastname, phone, email, company, role, address, website
5 Social profile Dynamic target_url
6 WiFi network Direct ssid, password, encryption (WPA | WEP | NOPASS), hidden
7 Pre-filled email Direct email_to, email_subject, email_body
8 Pre-filled SMS Direct sms_phone, sms_message
9 WhatsApp chat Direct wa_phone, wa_message
10 Phone call Direct phone_number
11 Text Direct text
12 Online document (PDF) Dynamic target_url
13 Calendar event Direct event_title, event_location, event_start, event_end, event_description
14 Map location Direct geo_lat, geo_lng

Event dates in the format 2026-10-20T18:00. Required field combinations are checked on creation: on error the 422 response says which field is missing.

Errors

Application errors use the format below: error is a message and code an identifier. Validation returns 400 with error, message and optional per-field errors; 401 may omit code, and 429 has no body: check the HTTP status and Retry-After.

{ "success": 0, "error": "…", "code": "plan_qr_limit" }
400 Invalid JSON or fields that do not match the schema: check message and errors.
401 API key missing, invalid or revoked.
403 The QR code isn't shared with you, your role isn't enough, or the plan quota is full.
404 QR code not found or deleted.
409 Conflict: for example a member already present or the last owner of a QR code.
422 Content rejected: missing field, invalid URL, unsupported type.
429 Too many requests: retry after the seconds given in Retry-After.