On this page
Getting started
Core objects
QR codes
Custom domains
Templates
Analytics
Webhooks
Reference
Introduction
The Qravio REST API lets you create, manage, and analyze QR codes programmatically. It’s available on the Pro and Agency plans. All requests are made over HTTPS and authenticated with an API key. Responses are JSON.
https://api.qravio.app/api/public/v1Authentication
Authenticate by sending your API key as a bearer token in the Authorization header (or the X-API-Key header). Create and manage keys in your dashboard under Developers. Keep keys secret — they carry full access to your workspace’s QR codes.
curl https://api.qravio.app/api/public/v1/qrcodes \
-H "Authorization: Bearer qr_live_your_api_key"
# Alternatively, use the X-API-Key header:
curl https://api.qravio.app/api/public/v1/qrcodes \
-H "X-API-Key: qr_live_your_api_key"Pagination
List endpoints return a paginated envelope with an items array plus total, page, page_size, and total_pages. Control the window with the query parameters below.
pageinteger1-based page number. Default 1.
page_sizeintegerItems per page. Default 20, max 100.
{
"items": [ /* … QR Code objects … */ ],
"total": 128,
"page": 2,
"page_size": 20,
"total_pages": 7
}Rate limits
Each workspace has a monthly call quota based on its plan. Every response includes rate-limit headers. Exceeding the quota returns 429 with a Retry-After header.
- Free / StarterNo API access
- Pro3,000 calls / month
- Agency25,000 calls / month
X-RateLimit-Limit: 25000
X-RateLimit-Remaining: 24871
X-RateLimit-Reset: 1781913600X-RateLimit-LimitintegerYour monthly call allowance.
X-RateLimit-RemainingintegerCalls remaining in the current period.
X-RateLimit-ResetintegerUnix epoch (seconds) when the quota resets.
Retry-AfterintegerOn 429 only — seconds until the quota resets.
Errors
Qravio uses standard HTTP status codes. Errors return a JSON body with a single detail message.
401UnauthorizedMissing, invalid, revoked, or expired API key.
402Payment RequiredYour plan’s QR-code limit (max_qr) is reached.
403ForbiddenWorkspace lacks api_access, or the QR type / feature isn’t in your plan.
404Not FoundThe resource doesn’t exist in your workspace.
422Unprocessable EntityRequest payload failed validation.
429Too Many RequestsMonthly call quota exceeded. See Retry-After.
503Service UnavailableQuota/usage lookup failed — retry shortly.
{
"detail": "API access requires a Pro or higher plan."
}The QR Code object
idstring (uuid)Unique identifier for the QR code.
workspace_idstring (uuid)The workspace that owns this QR code.
namestringDisplay name.
typestringQR type (e.g. website, vcard, business). See QR types.
categorystring"dynamic" (editable destination) or "static".
short_codestring | null6-char short code used in the scan URL.
preview_urlstring | nullPublic URL that renders a scannable SVG preview of this QR code. No API key required — safe to use directly in an <img> tag.
statusstring | null"active" or "inactive".
folder_idstring | nullParent folder, if organized into one.
custom_domain_idstring | nullVerified custom domain used for the short link.
ab_enabledbooleanTrue when an A/B test is active (>1 active website destination). Server-computed.
is_password_protectedbooleanTrue when a visitor password gate is active.
destinationsarray<Destination>Routing destinations (see below).
designobject | nullVisual design settings (dots, colors, logo, frame, output).
contentobject | nullType-specific content payload. See QR types.
total_scansintegerAll-time scan count.
created_bystring | nullUser who created the QR code.
created_atstring (ISO 8601) | nullCreation timestamp.
updated_atstring (ISO 8601) | nullLast update timestamp.
Destination object
idstring (uuid)Destination identifier.
target_urlstringThe URL this destination routes to.
weightinteger | nullA/B routing weight 0–100 (default 100).
is_activeboolean | nullWhether this destination is active.
labelstring | nullHuman-readable variant name.
variant_keystring | nullStable variant id (a, b, c…) used for sticky routing & analytics.
rulesobject | nullConditional routing rules (geo, device, time).
{
"id": "9f8b2c1a-1234-4d5e-8f90-abc123def456",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "Spring campaign",
"type": "website",
"category": "dynamic",
"short_code": "Ab3X9z",
"preview_url": "https://api.qravio.app/api/public/v1/preview/Ab3X9z.svg",
"status": "active",
"ab_enabled": false,
"is_password_protected": false,
"destinations": [
{
"id": "22222222-2222-2222-2222-222222222222",
"target_url": "https://example.com/spring",
"weight": 100,
"is_active": true,
"label": "Landing",
"variant_key": "a"
}
],
"content": { "url": "https://example.com/spring" },
"total_scans": 1240,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}The Analytics object
total_scansintegerAll-time total scans.
unique_scansintegerAll-time unique (session-deduplicated) visitors.
scans_todayintegerScans so far in the current UTC day.
wow_changenumberWeek-over-week change as a percentage.
daily_scansarray<{ date, scans }>Per-day series, clamped to your plan’s retention window.
scans_by_deviceobject{ mobile, tablet, desktop, bot } counts.
scans_by_countryobjectCountry code → scan count.
last_scanned_atstring (ISO 8601) | nullTimestamp of the most recent scan.
{
"total_scans": 1240,
"unique_scans": 980,
"scans_today": 42,
"wow_change": 12.5,
"daily_scans": [
{ "date": "2026-06-21", "scans": 58 },
{ "date": "2026-06-22", "scans": 42 }
],
"scans_by_device": { "mobile": 900, "tablet": 60, "desktop": 270, "bot": 10 },
"scans_by_country": { "US": 720, "IN": 310, "GB": 95 },
"last_scanned_at": "2026-06-22T11:02:00Z"
}QR codes
Create, list, update, and delete QR codes, and read their scan analytics.
/qrcodesList QR codes
Returns a paginated list of QR codes in the API key’s workspace, newest first. Supports filtering, search, sorting, and pagination.
Query parameters
folder_idstring (uuid)Only QR codes in this folder.
categorystring"dynamic" or "static".
statusstringFilter by status (active, inactive).
typestringFilter by QR type (website, vcard, …).
qstringCase-insensitive match on the QR name.
sortstring"created_at" (default) or "name".
orderstring"desc" (default) or "asc".
pageinteger1-based page number. Default 1.
page_sizeintegerItems per page. Default 20, max 100.
curl https://api.qravio.app/api/public/v1/qrcodes \
-H "Authorization: Bearer qr_live_your_api_key"{
"items": [
{ "id": "9f8b2c1a-…", "name": "Spring campaign", "type": "website", "total_scans": 1240, "…": "…" }
],
"total": 128,
"page": 1,
"page_size": 20
}/qrcodesCreate a QR code
Creates a QR code in your workspace. For dynamic QRs, include at least one destination. The content object shape depends on type — see QR types. Plan limits (max_qr) and allowed dynamic_qr_types are enforced.
Body parameters
namestringRequiredDisplay name.
typestringRequiredQR type (e.g. website, vcard, business).
categorystringRequired"dynamic" or "static".
contentobjectRequiredType-specific payload. See QR types.
destinationsarray<Destination>Required for dynamic QRs — where the code routes.
statusstringDefaults to "active".
folder_idstring (uuid)Organize into a folder.
custom_domain_idstring (uuid)Use a verified custom domain.
designobjectVisual design (dots, colors, logo, frame, output).
page_designobjectLanding-page theme for page-type QRs.
curl -X POST https://api.qravio.app/api/public/v1/qrcodes \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring campaign",
"type": "website",
"category": "dynamic",
"content": { "url": "https://example.com/spring" },
"destinations": [{ "target_url": "https://example.com/spring" }]
}'{ "id": "9f8b2c1a-…", "short_code": "Ab3X9z", "type": "website", "…": "…" }/qrcodes/bulkBulk-create QR codes
Creates up to 50 QR codes in a single request. Each item follows the same shape as Create a QR code. Requires the bulk-generation entitlement (Pro / Agency). Inserts run sequentially and are NOT rolled back if one item fails partway through the batch.
Body parameters
itemsarray<CreateQRCode>Required1–50 QR codes to create. Each item is a full create payload.
curl -X POST https://api.qravio.app/api/public/v1/qrcodes/bulk \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "name": "Table 1", "type": "website", "category": "dynamic",
"content": { "url": "https://example.com/t1" },
"destinations": [{ "target_url": "https://example.com/t1" }] },
{ "name": "Table 2", "type": "website", "category": "dynamic",
"content": { "url": "https://example.com/t2" },
"destinations": [{ "target_url": "https://example.com/t2" }] }
]
}'[ { "id": "…", "short_code": "…", "…": "…" }, { "id": "…", "…": "…" } ]/qrcodes/countsGet QR counts
Returns aggregate counts of QR codes in your workspace — the total, plus a breakdown per folder and per category. A cheap alternative to paging the whole list to build folder/category chips.
curl https://api.qravio.app/api/public/v1/qrcodes/counts \
-H "Authorization: Bearer qr_live_your_api_key"{
"total": 128,
"by_folder": { "0b1c…": 12, "7d2e…": 3 },
"by_category": { "dynamic": 110, "static": 18 }
}/qrcodes/{id}Retrieve a QR code
Fetches a single QR code by id.
Path parameters
idstring (uuid)RequiredThe QR code id. Must belong to your API key’s workspace.
curl https://api.qravio.app/api/public/v1/qrcodes/9f8b2c1a-1234-4d5e-8f90-abc123def456 \
-H "Authorization: Bearer qr_live_your_api_key"/qrcodes/{id}Update a QR code
Partially updates a QR code. Send only the fields you want to change. Passing destinations replaces all existing destinations.
Path parameters
idstring (uuid)RequiredThe QR code id. Must belong to your API key’s workspace.
Body parameters
namestringNew display name.
statusstring"active" or "inactive".
contentobjectUpdated type-specific content.
destinationsarray<Destination>Replaces all destinations.
designobjectUpdated design.
folder_idstring | nullMove to a folder, or null to remove.
passwordstringEnable a visitor password gate.
remove_passwordbooleanSet true to disable the password gate.
curl -X PATCH https://api.qravio.app/api/public/v1/qrcodes/9f8b2c1a-1234-4d5e-8f90-abc123def456 \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Summer campaign", "status": "active" }'/qrcodes/{id}Delete a QR code
Permanently deletes a QR code. Printed codes using this short link will stop working.
Path parameters
idstring (uuid)RequiredThe QR code id. Must belong to your API key’s workspace.
curl -X DELETE https://api.qravio.app/api/public/v1/qrcodes/9f8b2c1a-1234-4d5e-8f90-abc123def456 \
-H "Authorization: Bearer qr_live_your_api_key"{ "message": "QR code deleted successfully." }/qrcodes/{id}/analyticsGet QR analytics
Returns scan analytics for a QR code. The daily series is clamped to your plan’s retention window.
Path parameters
idstring (uuid)RequiredThe QR code id. Must belong to your API key’s workspace.
curl https://api.qravio.app/api/public/v1/qrcodes/9f8b2c1a-1234-4d5e-8f90-abc123def456/analytics \
-H "Authorization: Bearer qr_live_your_api_key"Folders
Organize QR codes into nested folders.
/foldersCreate a folder
Creates a folder in your workspace to organize QR codes. Folders are available on Starter and higher plans.
Body parameters
namestringRequiredFolder name.
parent_idstring (uuid) | nullNest under a parent folder, or omit for a top-level folder.
curl -X POST https://api.qravio.app/api/public/v1/folders \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Spring 2026" }'{
"id": "0b1c2d3e-4f56-4789-abcd-ef0123456789",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "Spring 2026",
"parent_id": null,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}/foldersList folders
Returns folders in your workspace. Filter by parent, or list only top-level folders.
Query parameters
parent_idstring (uuid)List only children of this folder.
rootbooleanWhen true, list only top-level (parent-less) folders.
curl https://api.qravio.app/api/public/v1/folders \
-H "Authorization: Bearer qr_live_your_api_key"[ {
"id": "0b1c2d3e-4f56-4789-abcd-ef0123456789",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "Spring 2026",
"parent_id": null,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
} ]/folders/treeGet folder tree
Returns the full recursive folder tree for your workspace. Each node includes a depth field.
curl https://api.qravio.app/api/public/v1/folders/tree \
-H "Authorization: Bearer qr_live_your_api_key"[ { "id": "0b1c…", "name": "Spring 2026", "parent_id": null, "depth": 0, "…": "…" } ]/folders/{id}Retrieve a folder
Fetches a single folder by id.
Path parameters
idstring (uuid)RequiredThe folder id. Must belong to your API key’s workspace.
curl https://api.qravio.app/api/public/v1/folders/0b1c2d3e-4f56-4789-abcd-ef0123456789 \
-H "Authorization: Bearer qr_live_your_api_key"{
"id": "0b1c2d3e-4f56-4789-abcd-ef0123456789",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "Spring 2026",
"parent_id": null,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}/folders/{id}Update a folder
Renames or moves a folder. Pass parent_id: null to move it to the top level.
Path parameters
idstring (uuid)RequiredThe folder id. Must belong to your API key’s workspace.
Body parameters
namestringNew folder name.
parent_idstring (uuid) | nullMove under a new parent, or null for top level.
curl -X PATCH https://api.qravio.app/api/public/v1/folders/0b1c2d3e-4f56-4789-abcd-ef0123456789 \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Spring 2026 — EU" }'{
"id": "0b1c2d3e-4f56-4789-abcd-ef0123456789",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "Spring 2026",
"parent_id": null,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}/folders/{id}Delete a folder
Deletes a folder. Sub-folders are deleted too (cascade); QR codes inside it are kept but become folder-less.
Path parameters
idstring (uuid)RequiredThe folder id. Must belong to your API key’s workspace.
curl -X DELETE https://api.qravio.app/api/public/v1/folders/0b1c2d3e-4f56-4789-abcd-ef0123456789 \
-H "Authorization: Bearer qr_live_your_api_key"{ "message": "Folder '…' deleted successfully." }/tagsCreate a tag
Creates a tag (campaign label) in your workspace. Idempotent by name — creating an existing tag returns it.
Body parameters
namestringRequiredTag name.
curl -X POST https://api.qravio.app/api/public/v1/tags \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "summer" }'{
"id": "aa11bb22-cc33-4d44-8e55-ff6677889900",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "summer",
"qr_count": 12,
"created_at": "2026-06-22T10:15:00Z"
}/tags/{id}Rename a tag
Renames a tag. The change applies everywhere the tag is used.
Path parameters
idstring (uuid)RequiredThe tag id. Must belong to your API key’s workspace.
Body parameters
namestringRequiredNew tag name.
curl -X PATCH https://api.qravio.app/api/public/v1/tags/aa11bb22-cc33-4d44-8e55-ff6677889900 \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "summer-2026" }'{
"id": "aa11bb22-cc33-4d44-8e55-ff6677889900",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"name": "summer",
"qr_count": 12,
"created_at": "2026-06-22T10:15:00Z"
}/tags/{id}Delete a tag
Deletes a tag and removes it from every QR code it was applied to. The QR codes themselves are kept.
Path parameters
idstring (uuid)RequiredThe tag id. Must belong to your API key’s workspace.
curl -X DELETE https://api.qravio.app/api/public/v1/tags/aa11bb22-cc33-4d44-8e55-ff6677889900 \
-H "Authorization: Bearer qr_live_your_api_key"{ "message": "Tag '…' deleted successfully." }Custom domains
Register and verify your own domains for QR short links.
/custom-domainsRegister a custom domain
Registers a custom domain for your workspace’s short links and returns the DNS records to add. Available on plans with custom-domain entitlement, up to your plan’s limit. The domain starts in "pending" until verified.
Body parameters
domainstringRequiredBare hostname, e.g. "links.example.com".
curl -X POST https://api.qravio.app/api/public/v1/custom-domains \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "domain": "links.example.com" }'{
"id": "d0aa11bb-22cc-4d33-8e44-ff5566778899",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"domain": "links.example.com",
"status": "pending",
"txt_record_name": "_qravio-challenge.links.example.com",
"txt_record_value": "qravio-verify=abc123…",
"cname_record_name": "links.example.com",
"cname_record_value": "cname.qravio.app",
"verified_at": null,
"created_at": "2026-06-22T10:15:00Z"
}/custom-domainsList custom domains
Returns all custom domains registered in your workspace.
curl https://api.qravio.app/api/public/v1/custom-domains \
-H "Authorization: Bearer qr_live_your_api_key"[ {
"id": "d0aa11bb-22cc-4d33-8e44-ff5566778899",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"domain": "links.example.com",
"status": "pending",
"txt_record_name": "_qravio-challenge.links.example.com",
"txt_record_value": "qravio-verify=abc123…",
"cname_record_name": "links.example.com",
"cname_record_value": "cname.qravio.app",
"verified_at": null,
"created_at": "2026-06-22T10:15:00Z"
} ]/custom-domains/{id}Retrieve a custom domain
Fetches a single custom domain, including its current verification status and DNS records.
Path parameters
idstring (uuid)RequiredThe custom domain id. Must belong to your API key’s workspace.
curl https://api.qravio.app/api/public/v1/custom-domains/d0aa11bb-22cc-4d33-8e44-ff5566778899 \
-H "Authorization: Bearer qr_live_your_api_key"{
"id": "d0aa11bb-22cc-4d33-8e44-ff5566778899",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"domain": "links.example.com",
"status": "pending",
"txt_record_name": "_qravio-challenge.links.example.com",
"txt_record_value": "qravio-verify=abc123…",
"cname_record_name": "links.example.com",
"cname_record_value": "cname.qravio.app",
"verified_at": null,
"created_at": "2026-06-22T10:15:00Z"
}/custom-domains/{id}Update a custom domain
Changes the domain name. This resets the domain to "pending" and issues fresh DNS records, so you must re-verify ownership.
Path parameters
idstring (uuid)RequiredThe custom domain id. Must belong to your API key’s workspace.
Body parameters
domainstringRequiredNew bare hostname.
curl -X PATCH https://api.qravio.app/api/public/v1/custom-domains/d0aa11bb-22cc-4d33-8e44-ff5566778899 \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "domain": "go.example.com" }'{
"id": "d0aa11bb-22cc-4d33-8e44-ff5566778899",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"domain": "links.example.com",
"status": "pending",
"txt_record_name": "_qravio-challenge.links.example.com",
"txt_record_value": "qravio-verify=abc123…",
"cname_record_name": "links.example.com",
"cname_record_value": "cname.qravio.app",
"verified_at": null,
"created_at": "2026-06-22T10:15:00Z"
}/custom-domains/{id}Delete a custom domain
Removes a custom domain. QR short links on this domain will stop resolving.
Path parameters
idstring (uuid)RequiredThe custom domain id. Must belong to your API key’s workspace.
curl -X DELETE https://api.qravio.app/api/public/v1/custom-domains/d0aa11bb-22cc-4d33-8e44-ff5566778899 \
-H "Authorization: Bearer qr_live_your_api_key"/custom-domains/{id}/verifyVerify a custom domain
Checks the domain’s TXT and CNAME DNS records and marks it verified when both resolve. Call after adding the records returned at creation.
Path parameters
idstring (uuid)RequiredThe custom domain id. Must belong to your API key’s workspace.
curl -X POST https://api.qravio.app/api/public/v1/custom-domains/d0aa11bb-22cc-4d33-8e44-ff5566778899/verify \
-H "Authorization: Bearer qr_live_your_api_key"{
"domain_id": "d0aa11bb-…",
"domain": "links.example.com",
"status": "verified",
"txt_verified": true,
"cname_verified": true,
"verified_at": "2026-06-22T10:20:00Z",
"detail": "Domain verified."
}Templates
Save and reuse QR design templates across your workspace.
/templatesCreate a design template
Saves a reusable QR design template. The design object is the same QR design JSON accepted by the design field when creating a QR code. Template names are unique per workspace.
Body parameters
namestringRequiredTemplate name (unique in the workspace).
designobjectRequiredQR design JSON (dots, colors, logo, frame, output).
descriptionstringOptional description.
categorystringe.g. "minimal", "bold", "corporate", "dark".
qr_typestringQR type this template targets (e.g. website, vcard_plus).
curl -X POST https://api.qravio.app/api/public/v1/templates \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Corporate blue",
"category": "corporate",
"design": { "dotsColor": "#4648d4", "backgroundColor": "#ffffff" }
}'{
"id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"created_by": "22222222-2222-2222-2222-222222222222",
"name": "Corporate blue",
"description": "Brand template for print",
"category": "corporate",
"qr_type": "website",
"design": { "dotsColor": "#4648d4", "…": "…" },
"usage_count": 4,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}/templatesList design templates
Returns your workspace’s design templates. Filter by category or the QR type they target.
Query parameters
categorystringFilter by category.
qr_typestringFilter by target QR type.
curl https://api.qravio.app/api/public/v1/templates \
-H "Authorization: Bearer qr_live_your_api_key"[ {
"id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"created_by": "22222222-2222-2222-2222-222222222222",
"name": "Corporate blue",
"description": "Brand template for print",
"category": "corporate",
"qr_type": "website",
"design": { "dotsColor": "#4648d4", "…": "…" },
"usage_count": 4,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
} ]/templates/{id}Retrieve a design template
Fetches a single design template by id.
Path parameters
idstring (uuid)RequiredThe template id. Must belong to your API key’s workspace.
curl https://api.qravio.app/api/public/v1/templates/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b \
-H "Authorization: Bearer qr_live_your_api_key"{
"id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"created_by": "22222222-2222-2222-2222-222222222222",
"name": "Corporate blue",
"description": "Brand template for print",
"category": "corporate",
"qr_type": "website",
"design": { "dotsColor": "#4648d4", "…": "…" },
"usage_count": 4,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}/templates/{id}Update a design template
Updates a template’s name, description, or category. Send only the fields you want to change.
Path parameters
idstring (uuid)RequiredThe template id. Must belong to your API key’s workspace.
Body parameters
namestringNew name.
descriptionstringNew description.
categorystringNew category.
curl -X PATCH https://api.qravio.app/api/public/v1/templates/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b \
-H "Authorization: Bearer qr_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Corporate blue v2" }'{
"id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"created_by": "22222222-2222-2222-2222-222222222222",
"name": "Corporate blue",
"description": "Brand template for print",
"category": "corporate",
"qr_type": "website",
"design": { "dotsColor": "#4648d4", "…": "…" },
"usage_count": 4,
"created_at": "2026-06-22T10:15:00Z",
"updated_at": "2026-06-22T10:15:00Z"
}/templates/{id}Delete a design template
Permanently deletes a design template. QR codes already using its design are unaffected.
Path parameters
idstring (uuid)RequiredThe template id. Must belong to your API key’s workspace.
curl -X DELETE https://api.qravio.app/api/public/v1/templates/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b \
-H "Authorization: Bearer qr_live_your_api_key"Analytics
Workspace-level scan analytics: summary, time series, devices, geography, heatmap, and conversion funnel.
/analytics/summaryWorkspace summary
Total scans, unique visitors, and week-over-week change across all QR codes in your workspace.
curl https://api.qravio.app/api/public/v1/analytics/summary \
-H "Authorization: Bearer qr_live_your_api_key"{ "total_scans": 18240, "unique_visitors": 13110, "scans_wow_change": 8.4 }/analytics/daysDay-wise scans
A daily scan time series for charting.
Query parameters
daysintegerLook-back window (1–90). Default 30.
curl "https://api.qravio.app/api/public/v1/analytics/days?days=14" \
-H "Authorization: Bearer qr_live_your_api_key"[ { "date": "2026-06-21", "scans": 421 }, { "date": "2026-06-22", "scans": 389 } ]/analytics/devicesDevice breakdown
Scan counts and percentages by device type. Requires advanced analytics (Pro+).
curl https://api.qravio.app/api/public/v1/analytics/devices \
-H "Authorization: Bearer qr_live_your_api_key"{
"mobile": 12800, "tablet": 640, "desktop": 4600, "bot": 200,
"mobile_pct": 70.2, "tablet_pct": 3.5, "desktop_pct": 25.2, "bot_pct": 1.1
}/analytics/top-countriesTop countries
Top countries by scan volume across the workspace. Requires advanced analytics (Pro+).
Query parameters
limitintegerMax rows (1–50). Default 5.
curl "https://api.qravio.app/api/public/v1/analytics/top-countries?limit=10" \
-H "Authorization: Bearer qr_live_your_api_key"[ { "country_code": "US", "scans": 9200 }, { "country_code": "IN", "scans": 4100 } ]/analytics/citiesTop cities
Top cities within a given country. Requires advanced analytics (Pro+).
Query parameters
countrystringRequiredISO country code (2–3 chars), e.g. US.
limitintegerMax rows (1–50). Default 10.
curl "https://api.qravio.app/api/public/v1/analytics/cities?country=US&limit=10" \
-H "Authorization: Bearer qr_live_your_api_key"[ { "city": "New York", "scans": 1820 }, { "city": "San Francisco", "scans": 1210 } ]/analytics/heatmapScan heatmap
A 7×24 matrix of scans by day-of-week (rows) and UTC hour (columns), with the peak cell. Requires advanced analytics (Pro+).
curl https://api.qravio.app/api/public/v1/analytics/heatmap \
-H "Authorization: Bearer qr_live_your_api_key"{
"matrix": [ [0,1,3, "…24 hours…"], "…7 days…" ],
"peak": { "day": 2, "hour": 14, "scans": 320 },
"bucketed_by": "utc_hour"
}/analytics/funnelConversion funnel
Scan → action (form submit / link click) conversion funnel for the workspace, or a single QR. Pass format=csv for a CSV download. Requires advanced analytics (Pro+).
Query parameters
qr_idstring (uuid)Limit the funnel to one QR code.
rangeintegerLook-back window in days (1–365). Default 30. Clamped to your plan’s retention.
exclude_botsbooleanExclude bot traffic. Default true.
formatstringSet to "csv" to download a CSV instead of JSON.
curl "https://api.qravio.app/api/public/v1/analytics/funnel?range=30" \
-H "Authorization: Bearer qr_live_your_api_key"
# CSV download:
curl "https://api.qravio.app/api/public/v1/analytics/funnel?range=30&format=csv" \
-H "Authorization: Bearer qr_live_your_api_key" -o funnel.csv{
"range_days": 30,
"qr_id": null,
"conversion_rate": 12.5,
"steps": [
{ "key": "scan", "label": "Scans", "count": 4000, "pct_of_previous": 100.0, "drop_off_pct": 0.0 },
{ "key": "action", "label": "Actions", "count": 500, "pct_of_previous": 12.5, "drop_off_pct": 87.5,
"breakdown": { "form_submit": 320, "link_click": 180 } }
]
}Leads
Read and export lead-form submissions captured by your QR landing pages.
/leadsList lead submissions
Returns lead-form submissions for your workspace, newest first. Each item includes the submitting QR code’s id and name plus the captured form data.
Query parameters
qr_idstring (uuid)Only submissions from this QR code.
limitintegerPage size (1–500). Default 50.
offsetintegerRow offset for pagination. Default 0.
curl "https://api.qravio.app/api/public/v1/leads?limit=50" \
-H "Authorization: Bearer qr_live_your_api_key"{
"items": [
{
"id": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
"qr_id": "9f8b2c1a-1234-4d5e-8f90-abc123def456",
"qr_name": "Trade-show booth",
"data": { "name": "Jane Doe", "email": "[email protected]", "company": "Acme" },
"submitted_at": "2026-06-22T10:15:00Z"
}
],
"total": 128
}/leads/export.csvExport leads as CSV
Streams all lead submissions as a CSV file. Columns are submitted_at, qr_name, and the union of every captured field across submissions.
Query parameters
qr_idstring (uuid)Only submissions from this QR code.
curl "https://api.qravio.app/api/public/v1/leads/export.csv" \
-H "Authorization: Bearer qr_live_your_api_key" -o leads.csvOutbound webhooks
Push scan and lead events to your own stack in real time — Zapier, Make, or a custom endpoint. Manage endpoints under Settings → Webhooks.
Free / Starter
No webhook access
—
Pro
3 endpoints
scan, lead.submitted
Agency
20 endpoints
scan, lead.submitted
Delivery headers
X-Qravio-EventstringThe event type — scan, lead.submitted, or ping.
X-Qravio-Timestampinteger (unix seconds)When the delivery was sent. Reject deliveries older than 5 minutes.
X-Qravio-Signaturestringsha256=<hex> — HMAC-SHA256 of "{timestamp}." + the raw request body, using your endpoint’s signing secret.
X-Qravio-Idempotency-Keystring (uuid)Dedupe key. A network retry of the same delivery reuses this key; a manual redeliver mints a new one.
scanFires for every scan of a QR code in the workspace, for any endpoint subscribed to it. Carries a hashed IP, never the raw address.
{
"event": "scan",
"id": "7c1f2e3a-1234-4d5e-8f90-abc123def456",
"created_at": "2026-06-24T10:00:00Z",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"data": {
"qr_id": "9f8b2c1a-1234-4d5e-8f90-abc123def456",
"country_code": "US",
"region": "CA",
"city": "San Francisco",
"device_type": "mobile",
"ip_hash": "a1b2c3d4e5f6…",
"session_id": "s_9f8b2c1a",
"scanned_at": "2026-06-24T10:00:00Z"
}
}lead.submittedFires when a visitor submits a Lead Capture form. Carries the submitted field values — enabling this endpoint is a customer-directed onward transfer of that lead’s PII.
{
"event": "lead.submitted",
"id": "7c1f2e3a-1234-4d5e-8f90-abc123def456",
"created_at": "2026-06-24T10:00:00Z",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"data": {
"qr_id": "9f8b2c1a-1234-4d5e-8f90-abc123def456",
"qr_name": "Booth A",
"fields": { "email": "[email protected]", "name": "Sam" }
}
}pingA synthetic test event sent by the "Send test ping" action in Settings → Webhooks — use it to verify your endpoint and signature check.
{
"event": "ping",
"id": "7c1f2e3a-1234-4d5e-8f90-abc123def456",
"created_at": "2026-06-24T10:00:00Z",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"data": { "message": "Qravio test ping" }
}Verify the signature
Compute hmac_sha256(secret, timestamp + "." + raw_body) and compare it to X-Qravio-Signature with a constant-time comparison. Reject deliveries whose timestamp is more than 5 minutes old, and dedupe retries on X-Qravio-Idempotency-Key.
import hmac, hashlib, time
def verify(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
if abs(time.time() - int(timestamp)) > 300:
return False # stale — possible replay
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)const crypto = require('crypto');
function verify(secret, timestamp, rawBody, signature) {
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false; // stale
const expected = crypto.createHmac('sha256', secret)
.update(`${timestamp}.`).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(`sha256=${expected}`), Buffer.from(signature));
}Retries
A failing delivery retries up to 4 times with backoff, then moves to dead_letter — redeliver it manually from the delivery log in Settings → Webhooks. An endpoint auto-pauses after 15 consecutive failures.
QR types
When creating a QR code, the content object’s shape depends on the type. Each type reads from one field below (* = required). Every plan can create every dynamic type but one — QR type is not a paywall lever here.
Every plan — Free included
All 15 dynamic types: website, pdf, images, vcard_plus, video, mp3, list_links, business, social_media, event, coupon, apps, location, menu, review_funnel.
Pro / Agency only
lead_form (Lead Capture) — the one type still behind a plan gate. What is paid is the capability: capturing, viewing and exporting submissions.
websitecontent.urlurl — the live target lives in destinations[]; content.url is the single-destination convenience formpdf / video / mp3content.fileContentfile_id*, file_path*, file_name*, content_type*, size_bytes*, version*imagescontent.imagesContentarray of fileContent objects (same required fields)vcard / vcard_pluscontent.vCardContentfirst_name*, last_name*, phone, email, company, job_title, website, bio, street_address, city, state, country, zip_codebusinesscontent.businessContentbusiness_name*, tagline, phone, email, website, street_address, city, state, postal_code, country, logo_url, business_hours, themelist_linkscontent.listOfLinkContentprofile_name*, bio, profile_url, links[] (id*, title*, url*, icon, position)social_mediacontent.socialMediaContentprofileName*, bio, instagram, facebook, twitter, linkedin, youtube, website, avatarUrl, coverUrleventcontent.eventContentevent_name*, start_date*, end_date*, start_time*, end_time*, timezone, location, description, organizer_name, rsvp_url, website_urlcouponcontent.couponContenttitle*, description, discountType, discountValue, couponCode, termsAndConditions, startDate, endDate, businessName, websiteappscontent.appContentappName*, appStoreUrl, playStoreUrl, companyName, description, websitelocationcontent.locationContentplace_name*, street_address, city, state, postal_code, country, landmark, latitude, longitude, phone, maps_url_override, open_directly (true → 302 to Maps, no landing page)menucontent.menuContentcurrency, menu_note, show_diet_marks, categories[] (name*, description, items[] → name*, price_minor (integer minor units), price_note, diet, is_available)review_funnelcontent.reviewFunnelContentgoogle_review_url* (must be a Google-operated host), star_threshold, rating_prompt, thank_you_message — pair with content.leadFormContent for the private-feedback steplead_formcontent.leadFormContentfields[] (name*, label*, type*, required*, options), success_message, redirect_url, notify_emailurlcontent.urlurltextcontent.texttextemailcontent.emailContentemail*, subject, bodysmscontent.smsContentnumber*, message*phonecontent.phoneContentnumber*whatsappcontent.whatsAppContentnumber*, messagewificontent.wifiContentnetwork_name*, encryption*, password, hiddenbitcoincontent.bitcoinContentaddress*, amount (BTC, ≤ 21,000,000, 8 dp), label, messageupicontent.upiContentpa*, pn, am, tn — INR only; cu is not acceptedpaypalcontent.paypalContentusername* (PayPal.me handle, not an email), amount, currency, noteStatic types (available on all plans): url, text, vcard, email, sms, phone, whatsapp, wifi, bitcoin, upi, paypal. A static QR encodes its payload in the pixels, so it has no short code, no editable destination and no scan analytics.