QR Codes
Account-scoped trackable QR codes — create, edit, stats and framed images.
QR codes belong to the Amba account, so these routes take a developer Bearer (a personal access token or a sign-in session) and no project id. Server keys and project-scoped tokens are refused with 403 QR_DEVELOPER_TOKEN_REQUIRED. See QR Codes for how scans, safety checks and plans work.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /qr | Create a code. |
| GET | /qr | List your codes, newest first. |
| GET | /qr/:id | One code with its destination history. |
| PATCH | /qr/:id | Edit a code or turn it off and on. |
| DELETE | /qr/:id | Delete a code. |
| GET | /qr/:id/stats | Daily series and, on Pro, breakdowns. |
| GET | /qr/:id/export.csv | Daily stats as CSV (Pro). |
| GET | /qr/:id/image | Framed SVG or PNG. |
| GET | /qr/me | Your display name and QR plan. |
| PATCH | /qr/me | Set the display name scanners see. |
| GET | /qr/billing | Your QR plan, subscription status and renewal date. |
| POST | /qr/billing/checkout | A checkout link for QR Pro ($10/month). |
| POST | /qr/billing/portal | A billing portal link (card, invoices, cancel). |
| POST | /qr/shares | Share some codes with a brand viewer. |
| GET | /qr/shares | List your shares. |
| DELETE | /qr/shares/:shareId | Turn a share link off. |
| GET | /qr/share-view/:token | A share's stats (no Bearer; the token is the credential). |
| POST | /auth/creator/start | Email a creator sign-up code (no Bearer). |
| POST | /auth/creator/verify | Redeem it for a session and PAT (no Bearer). |
The code object
status is active, disabled_owner (you turned it off) or disabled_safety (Amba turned it off for review). safety.verdict is pending, safe or unsafe. image_urls open without a Bearer until expires_at.
POST /qr
Request
| Field | Type | Required | Notes |
|---|---|---|---|
destination_url | string | yes | Absolute http(s) URL; must pass the safety checks |
label | string | no | Up to 200 characters; defaults to the destination domain |
platform | string | no | tiktok, instagram, youtube, x, snapchat, twitch, facebook, linkedin, other (default) |
post_url | string | no | http(s) link to the post |
campaign | string | no | Up to 100 characters; becomes utm_campaign |
sponsored | boolean | no | Default false |
sponsor_name | string | when sponsored | Up to 100 characters |
utm_mode | string | no | append (default) or off |
Response 201
Errors
400 INVALID_JSON— the body is not a JSON object.400 VALIDATION_ERROR— a field is malformed;details.fieldnames it.400 QR_DESTINATION_REJECTED— the destination breaks a safety rule;details.reasonnames it.400 QR_DESTINATION_UNSAFE— the destination is on the list of known malware and phishing sites.403 QR_ACCOUNT_UNVERIFIED— the account has no proven email address yet; claim it first.403 QR_ACCOUNT_SUSPENDED— Amba suspended QR codes on the account for review.429 QR_DAILY_CAP— the account's 24-hour cap on new codes is reached;details.limitgives it.429 RATE_LIMIT_EXCEEDED— more than 30 creates and destination changes in a minute; seeRetry-After.
Try it:
/qrcurl -X POST 'https://api.amba.dev/v1/qr' \
-H 'Content-Type: application/json' \
-d '{
"destination_url": "https://example.com/product",
"platform": "tiktok"
}'Curl:
GET /qr
Query: status (active, disabled or all, the default), limit (1 to 200, default 50), offset. Deleted codes are left out.
Try it:
/qrcurl -X GET 'https://api.amba.dev/v1/qr'Curl:
GET /qr/:id
The code object plus destination_history, newest first (the latest 500 changes):
404 QR_NOT_FOUND for a code that is not yours or was deleted.
Try it:
/qr/%7B%7BqrId%7D%7Dcurl -X GET 'https://api.amba.dev/v1/qr/%7B%7BqrId%7D%7D'Curl:
PATCH /qr/:id
Send any of the create fields, plus status (active or disabled_owner). post_url, campaign and sponsor_name accept null to clear. A changed destination_url runs the safety checks again, counts toward the destination-change cap, and is added to the destination history.
Errors
400 VALIDATION_ERROR,400 QR_DESTINATION_REJECTED,400 QR_DESTINATION_UNSAFE— as on create.404 QR_NOT_FOUND.403 QR_ACCOUNT_SUSPENDED— the account is suspended, and the change would turn the code on or change its destination.409 QR_DISABLED_FOR_SAFETY— Amba turned the code off for review; it cannot be edited.429 QR_DAILY_CAP— the 24-hour cap on destination changes is reached.
Try it:
/qr/%7B%7BqrId%7D%7Dcurl -X PATCH 'https://api.amba.dev/v1/qr/%7B%7BqrId%7D%7D' \
-H 'Content-Type: application/json' \
-d '{
"status": "disabled_owner"
}'Curl:
DELETE /qr/:id
Scanners see the turned-off page from then on. The slug is never given to another code.
Try it:
/qr/%7B%7BqrId%7D%7Dcurl -X DELETE 'https://api.amba.dev/v1/qr/%7B%7BqrId%7D%7D'Curl:
GET /qr/:id/stats
Query: from, to as YYYY-MM-DD (UTC). Defaults to the last 30 days; at most 400 days per request.
On the free plan, from moves up to 30 days ago, history_limited is true, and by_country / by_device_os are null. country is null when unknown. Bots and link previews are left out of every number. Visitor ids rotate daily, so totals.visitor_days adds up each day's unique_visitors.
Try it:
/qr/%7B%7BqrId%7D%7D/statscurl -X GET 'https://api.amba.dev/v1/qr/%7B%7BqrId%7D%7D/stats'Curl:
GET /qr/:id/image
Query: format (svg, the default, or png), size (pixels wide, 256 to 2048; PNG default 1024), and on Pro fg / bg hex colours. Without a Bearer, the request needs the exp and sig of a signed link from image_urls.
Errors
400 VALIDATION_ERROR— badformat,sizeor colour.400 QR_COLORS_LOW_CONTRAST—fgmust be darker thanbgwith a contrast ratio of at least 4:1.402 QR_PRO_REQUIRED— custom colours on the free plan.details.upgradenames the upgrade call (POST /qr/billing/checkout, MCPamba_qr_upgrade).429 RATE_LIMIT_EXCEEDED— more than 20 fresh PNG renders in a minute from one caller.404 QR_NOT_FOUND.
Try it:
/qr/%7B%7BqrId%7D%7D/imagecurl -X GET 'https://api.amba.dev/v1/qr/%7B%7BqrId%7D%7D/image'Curl:
GET /qr/:id/export.csv
Pro. The code's daily stats as CSV: one row per UTC day, country and device OS, the finest detail Amba keeps. Query: from, to as YYYY-MM-DD (UTC), both optional; without them the export covers the code's whole history. Bots and link previews are left out of every count, and country is empty when unknown.
Errors
402 QR_PRO_REQUIRED— CSV export on the free plan.details.upgradenames the upgrade call.400 VALIDATION_ERROR— a date that is notYYYY-MM-DD, orfromafterto.400 QR_EXPORT_TOO_LARGE— the range holds more than 200,000 rows; export a shorter one withfromandto.429 RATE_LIMIT_EXCEEDED— more than 10 exports in a minute from one account (Retry-Aftersays when to retry).404 QR_NOT_FOUND.
Try it:
/qr/%7B%7BqrId%7D%7D/export.csvcurl -X GET 'https://api.amba.dev/v1/qr/%7B%7BqrId%7D%7D/export.csv'Curl:
GET /qr/me
shown_as is what scanners see on the disclosure page ("An Amba creator" without a display name).
Try it:
/qr/mecurl -X GET 'https://api.amba.dev/v1/qr/me'Curl:
PATCH /qr/me
Body: { "display_name": "Sam Rivera" } (1 to 80 characters with no links, domains or "Amba"; null clears it). 400 VALIDATION_ERROR for a name that breaks those rules; 429 RATE_LIMIT_EXCEEDED past 10 changes an hour.
Try it:
/qr/mecurl -X PATCH 'https://api.amba.dev/v1/qr/me' \
-H 'Content-Type: application/json' \
-d '{
"display_name": "Sam Rivera"
}'Curl:
GET /qr/billing
Your account's QR plan. QR Pro is $10/month per account, billed apart from any project plan.
statusis the QR Pro subscription's status (active,trialing,past_due,canceled,unpaid,incomplete,incomplete_expired,paused), ornonebefore the first one.renews_atis the next renewal while the subscription renews.ends_atis set when a canceled subscription runs to the end of its paid period; the plan stays Pro until then.compedistruewhen Amba gave the account Pro at no charge.upgrade_availableistruewhenPOST /qr/billing/checkoutwould start a checkout.
The plan follows the subscription: Pro while it is active or trialing (and for 14 days while a failed renewal is retried), Free once it ends.
Try it:
/qr/billingcurl -X GET 'https://api.amba.dev/v1/qr/billing'Curl:
POST /qr/billing/checkout
No body. Returns a checkout link for QR Pro ($10/month) that the account owner opens to pay. Pro applies as soon as checkout completes, and the dashboard on go.amba.host/me is where checkout returns.
Errors
409 QR_PRO_ACTIVE— the account already has QR Pro: a subscription (usePOST /qr/billing/portalto manage it) or Pro at no charge from Amba.409 QR_PRO_PAYMENT_PENDING— the first payment of the account's QR Pro subscription is still being confirmed; it completes or expires within a day.409 QR_CHECKOUT_IN_PROGRESS— another checkout for the account is running; retry in a moment.403 QR_ACCOUNT_SUSPENDED,403 QR_ACCOUNT_UNVERIFIED— the same account checks as creating a code.503 QR_PRO_NOT_AVAILABLE— QR Pro is not available in this environment yet.502 QR_BILLING_UNAVAILABLE— the payment provider did not answer; retry.
Try it:
/qr/billing/checkoutcurl -X POST 'https://api.amba.dev/v1/qr/billing/checkout' \
-H 'Content-Type: application/json' \
-d '{}'Curl:
POST /qr/billing/portal
No body. Returns { "url": "…" }, a billing portal link where the account owner changes the card, reads invoices or cancels QR Pro. The portal covers QR Pro alone; project plans have their own (POST /admin/projects/:projectId/billing/portal).
Errors
409 QR_NO_SUBSCRIPTION— the account has no QR Pro billing yet; upgrade first.502 QR_BILLING_UNAVAILABLE— the payment provider did not answer; retry.
Try it:
/qr/billing/portalcurl -X POST 'https://api.amba.dev/v1/qr/billing/portal' \
-H 'Content-Type: application/json' \
-d '{}'Curl:
POST /qr/shares
Request
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Up to 200 characters, e.g. the brand |
viewer_email | string | yes | Amba emails the share link here |
qr_ids | string[] | yes | 1 to 100 of your code ids |
Response 201
url is returned only here. Anyone with it can view the share, so it goes to the viewer and to you.
Errors
400 VALIDATION_ERROR— a field is malformed, or a name carries a link, a domain or "Amba".403 QR_SHARE_LIMIT— the free plan keeps one active share.details.upgradenames the upgrade call.403 QR_ACCOUNT_SUSPENDED— Amba suspended QR codes on the account.404 QR_NOT_FOUND— a code id is not yours, or was deleted.409 QR_DISABLED_FOR_SAFETY— a code Amba turned off for safety cannot be shared.429 QR_DAILY_CAP— 20 shares per 24 hours, or 3 for the same viewer.503 QR_SHARES_NOT_AVAILABLE— brand shares open together with the brand dashboard page.
email_sent is false when the invitation could not go out (a daily email budget, a delivery failure); the share still works through url.
Try it:
/qr/sharescurl -X POST 'https://api.amba.dev/v1/qr/shares' \
-H 'Content-Type: application/json' \
-d '{
"name": "Acme",
"viewer_email": "brand@example.com",
"qr_ids": [
"{{qrId}}"
]
}'Curl:
GET /qr/shares
Try it:
/qr/sharescurl -X GET 'https://api.amba.dev/v1/qr/shares'Curl:
DELETE /qr/shares/:shareId
Try it:
/qr/shares/%7B%7BshareId%7D%7Dcurl -X DELETE 'https://api.amba.dev/v1/qr/shares/%7B%7BshareId%7D%7D'Curl:
GET /qr/share-view/:token
No Bearer: the token from the share link is the credential. Query: from, to as on stats, following the sharer's plan.
A code Amba turned off for safety appears with destination_url, destination_host and final_url set to null and an empty destination_history. 404 QR_SHARE_NOT_FOUND for an unknown or turned-off share, or one whose owner Amba suspended; 429 RATE_LIMIT_EXCEEDED past 60 views a minute from one caller or 30 a minute of one share.
Curl:
POST /auth/creator/start
No Bearer. Body: { "email": "sam@example.com" }. Emails a 6-digit code and answers { "data": { "ok": true } }.
400 DISPOSABLE_EMAIL— disposable addresses are refused.403 CREATOR_SIGNUPS_CLOSED— creator signups are closed right now.429 CREATOR_SIGNUPS_DAILY_CAP— the daily limit on new creator accounts is reached.429 RATE_LIMIT_EXCEEDEDor429 EMAIL_BUDGET_EXCEEDED— too many codes for this address or network.
Curl:
POST /auth/creator/verify
No Bearer. Body: { "email", "code", "display_name"? }.
pat is set only when the call creates the account. An address that already has an account signs in with pat: null and keeps its token.
400 INVALID_INPUT— a malformed field, or adisplay_namewith a link, a domain or "Amba".401 CREATOR_CODE_INVALID— the code is wrong, used, locked or expired.409 CREATOR_ACCOUNT_UNPROVEN— an Amba account that never proved this address uses it; sign in with a code fromPOST /v1/auth/developer/otp/request.409 EMAIL_EXISTS— another account owns this mailbox under an alias.
Curl: