Skip to content

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/codes accepts only url, vcard, wifi, email, sms, and location. Fields are flat: url; at least vcard_first_name or vcard_last_name; wifi_ssid; email_to; sms_phone; or both location_lat and location_lng.
  • Only url codes can be dynamic. Create requests may optionally include expires_at as an ISO-8601 timestamp; ab_enabled, ab_target_url_b and ab_weight_a (A/B destinations) are accepted for dynamic url codes; redirect_after_expiry is not part of the create contract.
  • GET /v1/codes supports only limit, cursor, and status (live, paused, flagged, draft).
  • POST /v1/codes/batch accepts url, vcard, and wifi. 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: true is required.

Create a QR Code

POST /v1/codes

Terminal window
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
}'

Response (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

Terminal window
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

Terminal window
GET /v1/codes?limit=20&status=live

Supported query parameters: limit, cursor, and status (live, paused, flagged, or draft).

Get a QR Code

GET /v1/codes/:id

Terminal window
GET /v1/codes/qr_a1b2c3d4

Update 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.

Terminal window
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"}'

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; label is 1–100 characters; url must be http(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

TypeContent encoded
urlURL or redirect short link
vcardvCard 3.0 contact information
wifiWi-Fi connection (SSID, password, encryption)
emailmailto: with pre-filled subject and body
smssmsto: with pre-filled message
locationgeo: 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 raster
GET /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.

Terminal window
# Add a comment
curl -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 comments
curl "https://qr3.app/v1/codes/qr_a1b2c3d4/comments?resolved=false" \
-H "Authorization: Bearer qr3_sk_..."
# Mark a comment as resolved
curl -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 }'