QR codes (qr_code)
Show a QR code to scan: a ticket, a check-in, Wi-Fi details, a link or a pickup code. Display only: the page asks for no answer.
When to use it: You show a QR code to scan: a ticket, a check-in code, Wi-Fi login details, a pickup number, or a link the person opens from another device. It only displays information; the person does not answer.
When not to use it: Do not use it to collect anything or to ask a question: a QR code returns no answer (use form or a picker). Do not use it for a link the person only needs to tap in chat: send the link itself.
Gather first:
- The exact text to encode: the ticket URL, the
WIFI:T:WPA;S:<network>;P:<password>;;string, or the check-in number, copied exactly as the scanner expects it. - A short label that says what the code is, and optionally a short code the person can type if scanning fails.
Writing good content:
- Put the scannable text in
valueonly. It is not shown in link previews, butdetails,labelandcaptionmay be (the caption appears unless validity text replaces it), so never put a password or ticket secret in them. valuecan be an https link, a Wi-Fi string, or plain text such as a ticket or pickup number. Links must be https; javascript:, data:, file:, vbscript: and blob: are rejected.valueis also limited by UTF-8 bytes pererrorCorrectionlevel: L 2,953, M 2,331, Q 1,663, H 1,273.- Set
codeto a short code for typing by hand when the scanner has a manual-entry option. Without it the page shows the value as text, or as an open-link button for an https link. - Add
validFromandvalidUntil(with the local UTC offset) for tickets and time-limited passes; they are shown as text and the code does not expire. - Use
detailsfor name, seat or venue, andcaptionfor one instruction such as "Show this at the door."
Display-only: the page shows information and has no Submit button. It accepts no answer, so no result ever comes back.
Fields
Every page also has version (always 1), title, and optionally description, branding, cover (a header photo), expiresAt and returnLink; see Page fields. These are the fields of page (the page type and its data):
| Field | Description |
|---|---|
value | string, required. The text the QR code encodes, up to 1,000 characters and, as UTF-8 bytes, at most 2,953 (errorCorrection L), 2,331 (M), 1,663 (Q) or 1,273 (H). Required. An https URL ("https://tickets.example.com/t/8F3K2"), a Wi-Fi login ("WIFI:T:WPA;S:Cafe Guest;P:espresso42;;"), or plain text such as a ticket or pickup number. Web links must be https; javascript:, data:, file:, vbscript: and blob: URLs are rejected. Not shown in link previews. Limits: 1-1000 characters. |
label | string, required. What the code is, shown above it, e.g. "Your ticket" or "Guest Wi-Fi". Required. Limits: 1-60 characters. |
caption | string. Optional sentence under the label, e.g. "Show this at the door." Include when helpful; omit otherwise. Limits: 1-200 characters. |
code | string. Optional short code shown in monospace under the QR for typing in by hand, e.g. "8F3K-2Q". Omit and the page shows value as text instead. Limits: 1-32 characters. |
details | object[]. Optional facts shown under the code, up to 6, e.g. [{ "label": "Name", "value": "Alex Kim" }, { "label": "Seat", "value": "12B" }]. They appear in the link preview, so never put passwords or other secrets here; those belong only in value. Limits: 1-6 items. |
details[].label | string, required. Row name, e.g. "Seat". Limits: 1-40 characters. |
details[].value | string, required. Row value, e.g. "12B". Limits: 1-80 characters. |
validFrom | ISO 8601 timestamp. Optional start of validity, ISO 8601 with offset, e.g. "2026-11-14T18:00:00-08:00". Shown as text. |
validUntil | ISO 8601 timestamp. Optional end of validity, same format. Must be after validFrom. Shown as text; the code itself does not expire. |
timeZone | string. Optional IANA time zone for validFrom and validUntil, e.g. "America/Los_Angeles". Omit and the offset written in them is used. |
errorCorrection | "L" | "M" | "Q" | "H". Optional error correction: L (7%), M (15%), Q (25%) or H (30%) of the code can be damaged and still scan. Omit for M. |
Why these are required: The text to encode and what it is. Web links must be https; javascript:, data:, vbscript:, file: and blob: values are rejected. Display-only: no answer.
When optional fields are left out: No caption; without code the value itself is shown as text under the code (as a link when it is https); no validity line or details; error correction M. Times use the timestamp's UTC offset without timeZone. The link preview shows label and details, never value.
Minimal example
Only the required fields:
{
"version": 1,
"title": "Your pickup code",
"page": {
"type": "qr_code",
"value": "PICKUP 4821",
"label": "Pickup code"
}
}Full example
{
"version": 1,
"title": "Your ticket to Rooftop supper club",
"description": "Show this at the door. One code admits both of you.",
"branding": {
"name": "Juniper Events",
"accentColor": "#0b7a5c"
},
"cover": {
"url": "https://images.example.test/rooftop-supper.jpg",
"alt": "A long dinner table set on a rooftop at dusk",
"focalPoint": {
"x": 0.5,
"y": 0.3
}
},
"page": {
"type": "qr_code",
"value": "https://tickets.juniper.example/t/8F3K2Q",
"label": "Your ticket",
"caption": "Scan at the door of The Lantern Room.",
"code": "8F3K-2Q",
"details": [
{
"label": "Name",
"value": "Alex Kim"
},
{
"label": "Admits",
"value": "2 people"
},
{
"label": "Venue",
"value": "The Lantern Room, 220 Pine Street"
}
],
"validFrom": "2026-11-14T18:30:00-08:00",
"validUntil": "2026-11-14T23:00:00-08:00",
"timeZone": "America/Los_Angeles"
}
}Send it
The pagesystems package and MCP
With the pagesystems package (eve, AI SDK and other frameworks) or the MCP server, the model calls get_page_type_schema with "qr_code" (the same JSON as GET /v1/page-types/qr_code), then create_page with this input (no version or branding; branding comes from your dashboard):
{
"title": "Your ticket to Rooftop supper club",
"description": "Show this at the door. One code admits both of you.",
"cover": {
"url": "https://images.example.test/rooftop-supper.jpg",
"alt": "A long dinner table set on a rooftop at dusk",
"focalPoint": {
"x": 0.5,
"y": 0.3
}
},
"page": {
"type": "qr_code",
"value": "https://tickets.juniper.example/t/8F3K2Q",
"label": "Your ticket",
"caption": "Scan at the door of The Lantern Room.",
"code": "8F3K-2Q",
"details": [
{
"label": "Name",
"value": "Alex Kim"
},
{
"label": "Admits",
"value": "2 people"
},
{
"label": "Venue",
"value": "The Lantern Room, 220 Pine Street"
}
],
"validFrom": "2026-11-14T18:30:00-08:00",
"validUntil": "2026-11-14T23:00:00-08:00",
"timeZone": "America/Los_Angeles"
}
}REST
curl https://pagesystems.ai/v1/pages \
-H "Authorization: Bearer $PAGE_SYSTEMS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"spec":{"version":1,"title":"Your ticket to Rooftop supper club","description":"Show this at the door. One code admits both of you.","branding":{"name":"Juniper Events","accentColor":"#0b7a5c"},"cover":{"url":"https://images.example.test/rooftop-supper.jpg","alt":"A long dinner table set on a rooftop at dusk","focalPoint":{"x":0.5,"y":0.3}},"page":{"type":"qr_code","value":"https://tickets.juniper.example/t/8F3K2Q","label":"Your ticket","caption":"Scan at the door of The Lantern Room.","code":"8F3K-2Q","details":[{"label":"Name","value":"Alex Kim"},{"label":"Admits","value":"2 people"},{"label":"Venue","value":"The Lantern Room, 220 Pine Street"}],"validFrom":"2026-11-14T18:30:00-08:00","validUntil":"2026-11-14T23:00:00-08:00","timeZone":"America/Los_Angeles"}}}'Validation errors
A spec that does not validate is refused with 400 invalid_spec. The message names each problem and its path, so a model can fix the spec and try again. For example:
Leaving out the required field value:
✖ Invalid input: expected string, received undefined
→ at page.valueMisspelling a field name (unknown keys are rejected):
✖ Unrecognized key: "colour"
→ at page