Skip to main content
A QR Code is returned as a JSON object with object: "qr_code".

Example

{
  "object": "qr_code",
  "id": "8f3a9d2e-1b4c-4f5d-9e8a-7c3b2a1d0f9e",
  "group_id": "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
  "public_slug": "abc1234",
  "url": "https://award.ee/abc1234",
  "name": "Front-of-house table card",
  "description": "Tabletop QR at Brunswick venue, fall 2024 menu.",
  "status": "active",
  "destination": {
    "type": "page",
    "chatbot": null,
    "page": "a1c2e4f6-8b0d-4e2a-9c1b-3d5e7f9a2c4e",
    "knowledge_base": null,
    "url": null
  },
  "total_scans": 4218,
  "last_scanned_at": "2026-05-22T19:13:08Z",
  "created_at": "2024-09-12T01:14:33Z",
  "updated_at": "2026-04-30T22:08:14Z"
}

Identifiers

object
string
required
Always "qr_code".
id
string (uuid)
required
Stable UUID. Use this in {id} path params — but public_slug is accepted there too.
public_slug
string
required
The short slug shown in the scan URL. 7–10 characters of [a-zA-Z0-9]. Stable for the life of the code — never regenerated, never reused. Path params accept this in lieu of the UUID.
url
string (url)
required
Fully qualified short URL. The address printed on the physical QR. Convenience field — derived from public_slug.
https://award.ee/abc1234

Label

name
string | null
Operator-facing label. Free-form. Not rendered to scanning visitors. Set it during print to keep dashboard navigation sane.
description
string | null
Free-form description. Operator-facing only.

Destination

destination
object
required
Where scans redirect. Always present as an object. Exactly one of chatbot, page, knowledge_base, or url is non-null when type is set.

Status & group

status
string
required
One of unconfigured, active, inactive, archived. See lifecycle.
group_id
string (uuid) | null
Parent QR Group id, or null if the code stands alone. When the group’s destination_type is set and the code’s own destination_type is null, scans inherit from the group. Detach by PATCHing group_id to null.

Stats

total_scans
integer
required
Lifetime count of redirected scans. Increments on qr_code.scanned. Read-only.
last_scanned_at
string (datetime) | null
ISO 8601 timestamp of the most recent scan, or null if never scanned. Read-only.

Timestamps

created_at
string (datetime)
required
When the code was minted. ISO 8601.
updated_at
string (datetime)
required
Last mutation timestamp. ISO 8601.

Scan object

GET /qr-codes/{id}/scans returns immutable scan rows in cursor-paginated reverse-chronological order.
{
  "object": "qr_scan",
  "id": "f1e2d3c4-5b6a-4978-8c0d-1e2f3a4b5c6d",
  "qr_code_id": "8f3a9d2e-1b4c-4f5d-9e8a-7c3b2a1d0f9e",
  "scanned_at": "2026-05-22T19:13:08Z",
  "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 …) Safari/605.1.15",
  "destination": {
    "type": "page",
    "id": "a1c2e4f6-8b0d-4e2a-9c1b-3d5e7f9a2c4e",
    "url": null
  },
  "query_params": { "utm_source": "poster", "utm_campaign": "fall24" },
  "location": {
    "country": "AU",
    "region": "VIC",
    "city": "Melbourne"
  }
}
destination
object
required
Snapshot of where this specific scan went. Captured at scan time so historical rows survive future destination changes.
query_params
object
required
The merged query params from the redirect: static params on the QR (and group) merged with whatever the visitor brought on the short URL. Live values win on key collision.
location
object
required
Coarse geolocation derived from the visitor IP. All three fields may be null if the lookup fails.
user_agent
string | null
Raw User-Agent header from the visitor’s request. null when absent.
IP address and Referer are deliberately not exposed on the wire — they’re collected for fraud detection but kept internal.

Properties and URL params

Both are flat lists of { key, value, sort_order } rows hung off the QR. Replace as a set with PUT:
{
  "id": "c4d5e6f7-8a9b-4c0d-1e2f-3a4b5c6d7e8f",
  "key": "utm_source",
  "value": "poster",
  "sort_order": 0,
  "created_at": "2024-09-12T01:14:33Z",
  "updated_at": "2024-09-12T01:14:33Z"
}
Properties are operator metadata (venue, batch, channel). URL params are appended to the redirect at scan time — see URL param merge.