QR Codes API
Overview
The Codes API is the core of qr3.app. Use it to create, update, and delete dynamic and static QR codes.
Base URL: https://qr3.app/v1/codes
Authoritative REST contract
The following contract applies to every client:
POST /v1/codesaccepts onlyurl,vcard,wifi,email,sms, andlocation. Fields are flat:url; at leastvcard_first_nameorvcard_last_name;wifi_ssid;email_to;sms_phone; or bothlocation_latandlocation_lng.- Only
urlcodes can be dynamic. Create requests may optionally includeexpires_atas an ISO-8601 timestamp;ab_enabled,ab_target_url_bandab_weight_a(A/B destinations) are accepted for dynamicurlcodes;redirect_after_expiryis not part of the create contract. GET /v1/codessupports onlylimit,cursor, andstatus(live,paused,flagged,draft).POST /v1/codes/batchacceptsurl,vcard, andwifi. Limits are 10 for Free, 500 for Pro, and 1,000 for Business, Agency, and Enterprise per request. URL scans run synchronously for at most 50 URL items; above 50,skip_url_scan: trueis required.
Create a QR Code
POST /v1/codes
curl -X POST https://qr3.app/v1/codes \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "type": "url", "url": "https://example.com", "title": "My first QR code", "tags": ["marketing", "q1"], "is_dynamic": true }'const code = await qr3.codes.create({ type: 'url', url: 'https://example.com', title: 'My first QR code', tags: ['marketing', 'q1'], is_dynamic: true,});qr3 create https://example.com --title "My QR code" --tags marketing,q1Response (HTTP 201):
{ "data": { "id": "qr_a1b2c3d4", "short_code": "r7f3Kx", "redirect_url": "https://qr3.app/r7f3Kx", "image_svg_url": "https://qr3.app/v1/codes/r7f3Kx/qr.svg", "image_png_url": "https://qr3.app/v1/codes/r7f3Kx/qr.png", "image_pdf_url": "https://qr3.app/v1/codes/r7f3Kx/qr.pdf", "image_eps_url": "https://qr3.app/v1/codes/r7f3Kx/qr.eps", "type": "url", "status": "live", "is_dynamic": true, "total_scans": 0, "created_at": "2026-03-15T10:00:00.000Z" }, "meta": { "request_id": "req_xyz" }}Batch creation
POST /v1/codes/batch
curl -X POST https://qr3.app/v1/codes/batch \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "items": [ { "type": "url", "url": "https://product-1.example.com", "tags": ["batch"] }, { "type": "url", "url": "https://product-2.example.com", "tags": ["batch"] }, { "type": "wifi", "wifi_ssid": "GuestWiFi", "wifi_password": "secret123" } ], "skip_url_scan": false }'Response (HTTP 201):
{ "data": { "created": [ { "id": "qr_...", "short_code": "abc123", "redirect_url": "https://qr3.app/abc123" }, { "id": "qr_...", "short_code": "def456", "redirect_url": "https://qr3.app/def456" }, { "id": "qr_...", "short_code": "ghi789", "status": "live" } ], "total": 3, "failed": 0 }}Per-request limits are 10 for Free, 500 for Pro, and 1,000 for Business, Agency, and Enterprise. For more than 50 URL items, set skip_url_scan: true (see the contract above).
List QR Codes
GET /v1/codes
GET /v1/codes?limit=20&status=liveSupported query parameters: limit, cursor, and status (live, paused, flagged, or draft).
Get a QR Code
GET /v1/codes/:id
GET /v1/codes/qr_a1b2c3d4Update a QR Code
PATCH /v1/codes/:id
Update contract: url may be changed only for an existing code with type: "url", and its value must start with http:// or https://. Other code types must not receive url; invalid requests return 422.
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{"url": "https://new-destination.com", "status": "live"}'Landing page & external links
For dynamic url codes you can set is_landing_page: true (on create or via PATCH). A scan then renders a qr3-hosted page listing the code’s public files and external links instead of redirecting. External links are sent as a links array:
{ "is_landing_page": true, "links": [ { "label": "Datasheet", "url": "https://example.com/datasheet.pdf" }, { "label": "Certificate", "url": "https://example.com/certificate.pdf" } ]}- 0–20 links per code;
labelis 1–100 characters;urlmust behttp(s)(≤ 2048 characters). - Each URL is checked with Google Web Risk — an unsafe URL returns
422. - If Web Risk is unreachable when you save, the link is still accepted but flagged for re-scan. A daily job re-checks stored links (and periodically re-checks clean ones) and automatically pauses the code if a link is later found unsafe.
- Sending
"links": []clears all links. See the Landing page guide.
Delete a QR Code
DELETE /v1/codes/:id
Soft-deletes the code. Active scans are preserved for analytics.
QR Code Types
| Type | Content encoded |
|---|---|
url | URL or redirect short link |
vcard | vCard 3.0 contact information |
wifi | Wi-Fi connection (SSID, password, encryption) |
email | mailto: with pre-filled subject and body |
sms | smsto: with pre-filled message |
location | geo: coordinates |
QR Code Images
Every code exposes four image URLs:
GET /v1/codes/:shortCode/qr.svg → SVG vector (scalable)GET /v1/codes/:shortCode/qr.png → PNG rasterGET /v1/codes/:shortCode/qr.pdf → Vector PDF (square by default, or A4)GET /v1/codes/:shortCode/qr.eps → EPS vector (pro print workflows)Optional query params: size (2–20 modules per pixel; SVG/PNG/EPS only), format (square default — code plus its required quiet zone, no A4 whitespace — or a4 for a printable sheet), title.
Comments
Comments enable feedback loops between agencies and their clients.
GET /v1/codes/:id/comments
POST /v1/codes/:id/comments
PATCH /v1/codes/:id/comments/:commentId
DELETE /v1/codes/:id/comments/:commentId
Comments created from the dashboard are attributed to the acting user (author_id); comments created with a plain API key stay unattributed (author_id: null). A comment can be deleted only by its own author or by an org_admin/ws_admin — a plain API key can delete only unattributed, API-created comments.
# Add a commentcurl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/comments \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "body": "Please match the QR code to the green background.", "author_name": "Jane Doe" }'
# List open commentscurl "https://qr3.app/v1/codes/qr_a1b2c3d4/comments?resolved=false" \ -H "Authorization: Bearer qr3_sk_..."
# Mark a comment as resolvedcurl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4/comments/cmt_xyz \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "resolved": true }'