API reference
Every operation of the OpenAPI document, 101 in all. Paste a key, fill in an example and send it from this page. A sandbox key (it starts with oqr_test_) makes test codes that never answer scans. Prefer your own tools? Import the Postman collection or read the guide with quickstarts.
It stays in this page and goes only to the oqrely API with each request you send.
Sending requests from the page needs JavaScript. Every example below also works as is with curl.
Versioning: A breaking change ships as a new version, with at least 12 months of notice before the old version stops.
codes19 endpoints
Fixed and editable codes: create, change, turn off and on, archive, trash, images.
GET /v1/codes
List codes. Scope: read.
Newest first. Filters combine. Sandbox keys list only sandbox codes.
Responses
200A page of codes.401403422429
POST /v1/codes
Create a fixed or editable code. Scope: write.
Editable codes get a short link on the main short domain unless `domain_id` names another. Send an `Idempotency-Key` header to retry safely.
{
"mode": "editable",
"type": "url",
"name": "Spring flyer",
"content": {
"url": "https://example.com/spring"
},
"tags": [
"print"
]
}Responses
201The new code.401403404409422429
GET /v1/codes/{id}
Get a code. Scope: read.
Responses
200The code.401403404429
PATCH /v1/codes/{id}
Change content, design, rules, link settings, name or folder. Scope: write.
Live on the next scan. Fields are applied in this order: content, design, rules, link, name, folder; the first refusal stops the rest. A destination change on a high-traffic code needs confirmation in the app (403 step_up_required).
{
"content": {
"url": "https://example.com/summer"
}
}Responses
200The updated code.401403404409422429
DELETE /v1/codes/{id}
Move a code to the trash. Scope: write.
The code stops working and can be restored for 30 days (POST /codes/{id}/restore); then it is purged and its short link is retired.
Responses
200The trashed code.401403404409422429
POST /v1/codes/{id}/turn-off
Turn an editable code off. Scope: write.
Responses
200The code in its new state.401403404409422429
POST /v1/codes/{id}/turn-on
Turn an editable code back on. Scope: write.
Responses
200The code in its new state.401403404409422429
POST /v1/codes/{id}/archive
Archive a code. Scope: write.
Responses
200The code in its new state.401403404409422429
POST /v1/codes/{id}/unarchive
Bring an archived code back. Scope: write.
Responses
200The code in its new state.401403404409422429
POST /v1/codes/{id}/restore
Restore a code from the trash. Scope: write.
Responses
200The code in its new state.401403404409422429
GET /v1/codes/{id}/image
Download the image of a code. Scope: read.
SVG, PNG, PDF or EPS with the code design. Counts against the daily API quota.
Responses
200The image.401403404409422429
POST /v1/codes/{id}/convert
Make an editable copy of a fixed code, or a fixed copy of an editable one. Scope: write.
A new code; the original stays as it is. A fixed copy holds the editable code's current content.
Responses
201The new code.401403404409422429
POST /v1/codes/{id}/domain
Move an editable code to another domain. Scope: write.
Its short link moves to that domain. A code that was already downloaded or exported needs `confirm_breaks_printed: true`, because printed copies stop working.
{
"domain_id": "5ca1ab1e-c0de-4a11-8e5e-0d0c5a3b1e01"
}Responses
200The code.401403404409422429
GET /v1/codes/{id}/print-record
The note and print runs of a code. Scope: read.
Responses
200The print record.401403404422429
PATCH /v1/codes/{id}/note
Set the note of a code. Scope: write.
Up to 2,000 characters; an empty note removes it.
{
"note": "Printed for the spring fair."
}Responses
200The print record.401403404409422429
POST /v1/codes/{id}/print-runs
Record a print run of a code. Scope: write.
{
"quantity": 500,
"medium": "Flyer A5",
"printed_on": "2026-10-01",
"printer": "City Print"
}Responses
201The print record.401403404409422429
DELETE /v1/codes/{id}/print-runs/{run_id}
Remove a print run from a code. Scope: write.
Responses
200The print record.401403404409422429
POST /v1/codes/{id}/check-again
Ask for a new check of a held code. Scope: write.
When the automatic link check held a code, this runs it again now (10 times a day per code).
Responses
202The check is queued.401403404409422429
GET /v1/destinations/broken
Editable codes whose destination is down. Scope: read.
Open incidents of the daily destination check, newest first: the code, its URL, the last status or error and since when it fails. A code leaves the list when its destination answers again.
Responses
200A page of broken destinations.401403404422429
tags3 endpoints
Tags of the code library.
POST /v1/codes/{id}/tags
Add a tag to a code. Scope: write.
Creates the tag in the workspace when it is new.
{
"name": "print"
}Responses
200The code with its tags.401403404409422429
DELETE /v1/codes/{id}/tags/{name}
Remove a tag from a code. Scope: write.
Responses
200The code with its tags.401403404409422429
GET /v1/tags
List tags. Scope: read.
With the number of codes (outside the trash) carrying each tag.
Responses
200A page of tags.401403422429
analytics6 endpoints
Scan counts and raw scan events.
GET /v1/codes/{id}/scans
Scan counts of a code. Scope: read.
Human scans per UTC day, or summed per country or device code, over a range of up to 366 days.
Responses
200Totals and groups.401403404422429
GET /v1/codes/{id}/scans/events
Raw scan events of a code. Scope: raw_events.
Newest first, one row per human scan, without any visitor identifier. Needs the raw_events scope (Business and up).
Responses
200A page of scan events.401403404422429
POST /v1/codes/{id}/counter/reset
Set the scan counter of an editable code back to 0. Scope: write.
The analytics history stays; only the counter (and scan limits that read it) starts again.
Responses
200Reset.401403404409422429
GET /v1/scans/export
Export the scans of the workspace. Scope: read.
CSV or XLSX for the range (default 30 days). Small exports come back at once (200); larger ones are prepared in the background (202 with the export to fetch).
Responses
200The spreadsheet.401403404413422429
GET /v1/scans/exports/{id}
Download a prepared scan export. Scope: read.
404 until it is ready, and after it expires.
Responses
200The spreadsheet.401403404422429
GET /v1/scans/realtime
Scans of the last 60 minutes. Scope: read.
Human scans per minute and the latest scans, for the workspace or one code.
Responses
200The last hour.401403404422429
render1 endpoint
Static images without storing anything.
POST /v1/render
Render a static code image. Scope: render.
Encodes `text` as given, or builds the text from a typed `payload` (the same types as the generator). Returns the image bytes. Daily quota: the plan `api.render` value.
{
"payload": {
"type": "url",
"url": "https://example.com/menu"
},
"format": "svg"
}Responses
200The image.401403413422429
folders4 endpoints
Folders of the code library.
GET /v1/folders
List folders. Scope: read.
Responses
200A page of folders.401403422429
POST /v1/folders
Create a folder. Scope: write.
{
"name": "Spring campaign"
}Responses
201The new folder.401403404422429
DELETE /v1/folders/{id}
Delete a folder. Scope: write.
Codes in it move to the top level; nothing is deleted with it but its subfolders.
Responses
200The deleted folder.401403404429
POST /v1/folders/{id}/restore
Bring back a deleted folder. Scope: write.
The folder, its subfolders and the codes that were in them, unless they moved since.
Responses
200Restored.401403404409422429
domains9 endpoints
Domains codes can use; adding, checking and removing custom domains.
GET /v1/domains
List domains codes can use. Scope: read.
The oqrely short domains and the custom domains of the workspace. Add and verify custom domains in the app.
Responses
200A page of domains.401403422429
POST /v1/domains
Add a custom domain. Scope: write.
Returns the DNS record to set. The first check is queued at once; call POST /domains/{id}/check to check again. Apex domains need a provider that flattens CNAMEs (send `flattening_confirmed: true`).
{
"hostname": "qr.example.com"
}Responses
201The new domain, waiting for DNS.401403404409422429
GET /v1/domains/{id}
Get a custom domain with its setup status. Scope: read.
Responses
200The domain.401403404422429
DELETE /v1/domains/{id}
Remove a custom domain. Scope: write.
Printed codes on it stop working. Send the hostname as `confirm` to say you mean it.
Responses
200The removed domain.401403404409422429
POST /v1/domains/{id}/check
Check DNS, TLS or health now. Scope: write.
One check for the current setup step, as the setup screen runs while you wait.
Responses
200The domain after the check.401403404409422429503
POST /v1/domains/{id}/default
Make a domain the default for new codes. Scope: write.
Send `unset: true` to go back to the main short domain.
{
"unset": false
}Responses
200The domain.401403404409422429
PATCH /v1/domains/{id}/site
Set what the domain root and unknown links answer. Scope: write.
Modes: redirect (to `site_url`), link_list (a page with up to 20 links) or not_found.
{
"root_mode": "redirect",
"site_url": "https://example.com"
}Responses
200The domain.401403404409422429
POST /v1/domains/{id}/release-slugs
Release links a previous owner retired on this domain. Scope: write.
Needs a DNS check that verified the domain since you added it, and `confirm: true`: scanners of those old printed codes then reach your links.
{
"confirm": true
}Responses
200How many retired links were released.401403404409422429
POST /v1/destination-domains/verify
Prove you control a destination domain. Scope: write.
Checks the DNS TXT record or the meta tag (`oqrely-verify`) on the destination site. A verified domain lifts the trial rule on new destination domains.
{
"domain": "example.com"
}Responses
200The verification: the token to publish and whether it was found.401403404409422429
workspaces14 endpoints
Workspaces of the account, client workspaces, branding and GA4.
GET /v1/workspaces
List the workspaces of the account. Scope: read.
A key works in one workspace; this lists every workspace of the same account.
Responses
200A page of workspaces.401403422429
POST /v1/workspaces
Create a workspace. Scope: write.
Within the plan's workspaces. The key keeps working in its own workspace; create a key in the new one to use it.
{
"name": "Events"
}Responses
201The new workspace.401403404409422429
GET /v1/workspaces/current
The workspace of this key. Scope: read.
Responses
200The workspace.401403429
PATCH /v1/workspaces/current
Rename the workspace of this key. Scope: write.
{
"name": "Marketing"
}Responses
200Renamed.401403404409422429
GET /v1/clients
List client workspaces. Scope: read.
Agency plans: the client workspaces of the account with their codes, scans and members.
Responses
200A page of client workspaces.401403404422429
POST /v1/clients
Create a client workspace. Scope: write.
{
"name": "Corner Bakery"
}Responses
201The new client workspace.401403404409422429
POST /v1/clients/{pub_id}/invites
Invite someone to a client workspace. Scope: write.
Returns the invitation link once.
{
"email": "[email protected]",
"role": "viewer"
}Responses
201The invitation.401403404409422429
POST /v1/clients/{pub_id}/brand-kit
Choose the brand kit of a client workspace. Scope: write.
Its colours and logo brand what the client's scanners see. Leave `brand_kit_id` out to clear it.
{
"brand_kit_id": null
}Responses
200The client's branding.401403404409422429
POST /v1/clients/{pub_id}/copy
Copy codes between your workspace and a client workspace. Scope: write.
Up to 50 codes per call. Copies get new short links; the originals stay.
{
"direction": "to_client",
"code_ids": [
"5ca1ab1e-c0de-4a11-8e5e-0d0c5a3b1e01"
]
}Responses
200How many were copied.401403404409422429
GET /v1/branding
The branding scanners see. Scope: read.
Responses
200The workspace branding.401403404422429
PATCH /v1/branding
Change the branding scanners see. Scope: write.
Display name, logo (an uploaded image file), accent colour or a brand kit, on plans with custom branding.
{
"display_name": "Corner Bakery",
"accent": "#0B6E4F"
}Responses
200The workspace branding.401403404409422429
GET /v1/integrations/ga4
The GA4 connection of the workspace. Scope: read.
Whether every human scan is sent to a GA4 web stream as a `qr_scan` event. The API secret is never shown.
Responses
200The connection.401403404422429
POST /v1/integrations/ga4
Send scans to GA4. Scope: write.
A measurement id (G-...) and a Measurement Protocol API secret from your GA4 web stream.
{
"measurement_id": "G-ABCD1234",
"api_secret": "secret-from-ga4"
}Responses
200The connection.401403404409422429
DELETE /v1/integrations/ga4
Stop sending scans to GA4. Scope: write.
Responses
200The connection.401403404409422429
templates1 endpoint
Design, page and print templates.
GET /v1/templates
List templates. Scope: read.
Published oqrely templates and the templates of the workspace.
Responses
200A page of templates.401403422429
webhooks7 endpoints
Webhook endpoints, deliveries and replay.
GET /v1/webhooks
List webhook endpoints. Scope: read.
Responses
200Every endpoint of the workspace (at most 20).401403429
POST /v1/webhooks
Add a webhook endpoint. Scope: write.
The response carries the signing secret once; store it. URLs must use https and reach a public address.
{
"url": "https://hooks.example.com/oqrely",
"events": [
"code.created",
"code.updated"
]
}Responses
201The endpoint with its secret.401403404409422429
GET /v1/webhooks/{id}
Get a webhook endpoint. Scope: read.
Responses
200The endpoint.401403404429
PATCH /v1/webhooks/{id}
Change a webhook endpoint. Scope: write.
Send `enabled: true` to turn an endpoint back on after it was turned off for failing.
{
"events": [
"code.created",
"code.deleted"
]
}Responses
200The endpoint.401403404409422429
DELETE /v1/webhooks/{id}
Delete a webhook endpoint. Scope: write.
Its delivery log goes with it.
Responses
200The deleted endpoint.401403404429
GET /v1/webhooks/{id}/deliveries
Delivery log of an endpoint. Scope: read.
Newest first, each delivery with every attempt (time, status code, duration, error). Kept 30 days.
Responses
200A page of deliveries.401403404422429
POST /v1/webhooks/{id}/deliveries/{delivery}/replay
Send a delivery again. Scope: write.
Queues the identical body (same event id) as a new delivery, signed with a fresh timestamp.
Responses
201The new delivery.401403404429
pages11 endpoints
Hosted pages behind editable codes: structured fields, draft blocks, publish.
GET /v1/pages
List hosted pages. Scope: read.
Newest change first, with whether each is published.
Responses
200A page of hosted pages.401403404422429
POST /v1/pages
Create a hosted page from structured fields. Scope: write.
A new editable code with a draft page: a title, an optional subtitle and text, and up to 20 links. Publish it with POST /pages/{id}/publish.
{
"title": "Spring menu",
"text": "Fresh every morning.",
"links": [
{
"label": "Book a table",
"url": "https://example.com/book"
}
]
}Responses
201The new page (a draft).401403404409422429
GET /v1/pages/{id}
Get a hosted page with its draft blocks. Scope: read.
Responses
200The page.401403404422429
PATCH /v1/pages/{id}
Save the draft blocks of a page. Scope: write.
Adding, changing, moving and removing blocks: send the whole block list. Scanners keep the published version until you publish.
{
"blocks": [
{
"id": "hd",
"type": "header",
"title": "Spring menu"
}
]
}Responses
200The page with its new draft.401403404409422429
POST /v1/pages/{id}/publish
Publish the draft of a page. Scope: write.
Live on the next scan. Refused with 409 and the issues while the draft has publishing errors.
Responses
200The published page.401403404409422429
POST /v1/pages/{id}/unpublish
Take a page offline. Scope: write.
Responses
200The page, unpublished.401403404409422429
POST /v1/pages/{id}/revert
Bring back an earlier published version. Scope: write.
The chosen version becomes the live page again.
{
"version": 1
}Responses
200The page.401403404409422429
PATCH /v1/pages/{id}/settings
Change the settings and theme of a page. Scope: write.
Fields you leave out keep their value. `brand_kit_id` applies a brand kit: its colour, typeface and logo.
{
"settings": {
"title": "Spring menu"
},
"theme": {
"accent": "#0B6E4F"
}
}Responses
200The page.401403404409422429
POST /v1/pages/{id}/languages
Add a language version of a page. Scope: write.
Scanners see the version in their browser language. It starts as a copy of the main language.
{
"lang": "de"
}Responses
200The page.401403404409422429
PATCH /v1/pages/{id}/languages/{lang}
Set the title and description of a language version. Scope: write.
{
"title": "Speisekarte",
"description": "Frisch jeden Morgen."
}Responses
200The page.401403404409422429
DELETE /v1/pages/{id}/languages/{lang}
Remove a language version of a page. Scope: write.
Responses
200The page.401403404409422429
submissions1 endpoint
Form responses collected by hosted pages.
GET /v1/pages/{id}/submissions
List the form responses of a page. Scope: read.
Newest first. Needs the analytics permission in the workspace, like the responses inbox.
Responses
200A page of form responses.401403404422429
files4 endpoints
Uploading and listing PDFs and images.
GET /v1/files
List uploaded files. Scope: read.
PDFs and images of the workspace, newest first. Upload new files in the app.
Responses
200A page of files.401403404422429
POST /v1/files
Upload a PDF or an image. Scope: write.
The file as base64 in JSON. It is checked for malware and type before it can be used (status processing, then ready). Uploading the same bytes again returns the existing file with status 200.
{
"name": "menu.png",
"content_base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg=="
}Responses
201The uploaded file.401403409413415422429
DELETE /v1/files/{id}
Delete a file. Scope: write.
It leaves the file list and the storage meter; pages that still show it keep working until it is purged.
Responses
200The deleted file.401403404409422429
GET /v1/files/{id}/link
Get a short-lived link to a file. Scope: read.
A signed link to view (or with `download=true`, download) a ready file.
Responses
200The link.401403404422429
members7 endpoints
Members of the workspace, their roles and invitations.
GET /v1/members
List the members of the workspace. Scope: read.
Responses
200A page of members.401403404422429
GET /v1/members/invites
List open invitations. Scope: read.
Responses
200Open invitations.401403404422429
POST /v1/members/invites
Invite someone to the workspace. Scope: write.
Returns the invitation link once. It works for that e-mail address only, once, for 7 days.
{
"email": "[email protected]",
"role": "editor"
}Responses
201The invitation.401403404409422429
DELETE /v1/members/invites/{id}
Withdraw an invitation. Scope: write.
Responses
200Withdrawn.401403404409422429
PATCH /v1/members/{user_id}
Change the role of a member. Scope: write.
{
"role": "viewer"
}Responses
200The member with the new role.401403404409422429
DELETE /v1/members/{user_id}
Remove a member. Scope: write.
Their codes move to you; their API keys and assistant connections in this workspace stop.
Responses
200Removed.401403404409422429
PATCH /v1/members/{user_id}/folders
Limit a member to some folders. Scope: write.
An empty list gives the member the whole workspace again.
{
"folder_ids": []
}Responses
200The member's folders.401403404409422429
bulk9 endpoints
Bulk jobs that create many codes at once: preview, dry run, apply, undo, report.
GET /v1/bulk
List bulk jobs. Scope: read.
Responses
200A page of bulk jobs.401403404422429
POST /v1/bulk
Create many codes in one job. Scope: write.
Rows of url, name and tags. A request larger than the plan's bulk rows is refused before anything is created.
{
"mode": "editable",
"rows": [
{
"url": "https://example.com/a",
"name": "Table 1"
}
]
}Responses
202The queued job.401403404409422429
GET /v1/bulk/{id}
Get a bulk job with its counts. Scope: read.
Responses
200The job.401403404422429
POST /v1/bulk/{id}/cancel
Stop a running bulk job. Scope: write.
Rows already done stay done.
Responses
200The job.401403404409422429
POST /v1/bulk/preview
Check rows before a bulk job. Scope: write.
Validates every row against the plan's bulk rows and the code rules, without creating anything. Then POST /bulk (or with `dry_run: true`, a dry run you apply later).
{
"mode": "editable",
"rows": [
{
"url": "https://example.com/a",
"name": "Table 1"
}
]
}Responses
200The validation report.401403404409422429
POST /v1/bulk/{id}/apply
Apply a dry run. Scope: write.
Runs the planned rows of a finished dry run for real.
Responses
202The queued job.401403404409422429
POST /v1/bulk/{id}/undo
Undo a bulk update. Scope: write.
Puts back what an update job changed, within 24 hours of the run.
Responses
200How many codes were put back.401403404409410422429
GET /v1/bulk/{id}/report
The rows of a bulk job with their result. Scope: read.
Responses
200A page of rows.401403404422429
GET /v1/bulk/{id}/files/{name}
Download the ZIP of codes or the print sheet of a job. Scope: read.
`name` is codes.zip or sheet.pdf, as the job made them.
Responses
200The file.401403404422429
brand kits5 endpoints
Brand kits: colors, logos and style for new codes.
GET /v1/brand-kits
List brand kits. Scope: read.
Colors, logos and style the workspace applies to new codes. Pass a kit's design to codes.create as `design`.
Responses
200A page of brand kits.401403404422429
POST /v1/brand-kits
Create a brand kit. Scope: write.
{
"name": "Main brand",
"colors": {
"brand": "#0B6E4F",
"background": "#FFFFFF",
"accent": "#F2A541",
"light": "#E8F5EE"
},
"frameId": null,
"domainId": null
}Responses
201The new kit.401403404409422429
PATCH /v1/brand-kits/{id}
Change a brand kit. Scope: write.
Send the whole kit, as for create.
{
"name": "Main brand",
"colors": {
"brand": "#0B6E4F",
"background": "#FFFFFF",
"accent": "#F2A541",
"light": "#E8F5EE"
},
"frameId": null,
"domainId": null
}Responses
200The kit.401403404409422429
DELETE /v1/brand-kits/{id}
Delete a brand kit. Scope: write.
Codes keep their design.
Responses
200The deleted kit.401403404409422429
POST /v1/brand-kits/{id}/default
Make a brand kit the default for new codes. Scope: write.
Responses
200The kit.401403404409422429