API & integration docs
How codes resolve, what each payload type contains, and the import format.
On the REST API:a public read/write API is on the roadmap and listed under the Enterprise plan, but it isn't shipped yet — so it isn't documented here. What follows is what you can rely on today. If you need programmatic access now, email hello@peekinside.ioand tell us what you're building.
Code resolution
Every printed code encodes exactly one URL:
https://peekinside.io/q/<short_id>
The short_id is assigned once and is immutable— enforced by a database trigger, not just convention. You can change a code's type, payload, title and styling as often as you like and the printed sticker keeps working.
What a scan returns
- 307 to a destination — for links, app links, crypto URIs, conditional routes, and the
mailto:/tel:/sms:/geo:handoffs. - 307 to
/p/<short_id>— for anything that renders a hosted page: moving boxes, stock items, checklists, text, PDFs, galleries, link pages, lead forms and Wi-Fi. - 200 with a generated file —
text/vcardfor contacts,text/calendarfor events. - 307 to
/access-deniedfor a private code scanned by someone who isn't the owner, and/not-foundfor an unknown id.
Caching
Resolution responses are sent no-store and are never cached at the CDN. Two reasons: an edit has to take effect on the very next scan, and every scan has to reach the server to be recorded. The database lookup behind it is cached briefly and invalidated the moment you save a change.
Destination safety
Destinations are checked against an allow-list before they're served. javascript:, data:, vbscript:, file: and blob:are rejected, in redirects and in rendered links alike. Custom app schemes are permitted only for App link and Crypto codes, which is what they're for.
Payload types
Three routing categories:
Instant routing
url— a web address.app_link— a native app scheme with an optional web fallback.crypto— a wallet URI with an optional amount.conditional— different destinations by OS, optionally by time of day.
Hosted pages
moving_box— box number, rooms, fragile flag, contents, and a packing status you advance by scanning.stock_item— quantity, SKU, unit, bin location and a reorder threshold.inventory— a plain interactive checklist.rich_text— a text page.pdf— an embedded document.media— an image and video gallery.link_tree— a link-in-bio page.lead_form— a form whose submissions are saved to your account.wifi— network name with a one-tap password copy.
Native handoffs
vcard,ical,email,sms,phone,location
CSV import format
Bulk create accepts one file covering every type. Download the template from Bulk create → CSV import — it ships with a worked example row per type, and a column reference alongside it.
Rules
- The header must match the template exactly. Missing or unexpected columns reject the whole file rather than importing part of it.
- Every row needs a
type. Fill only the columns that type uses. - Lists use
|between items. Items with parts use::— for exampleDocs::https://example.comfor a link, orEmail::email::yesfor a form field. - Booleans accept
yes/no,true/false,1/0. - URLs must be
httporhttps. - 500 rows per import.
- Row errors are reported with line numbers and nothing is createduntil they're fixed.
Getting data out
- Scan log — Reporting → Export CSV. Time, code, IP, city/region/country, coordinates, device, referrer and user agent.
- Codes — export any code as PNG at up to 4096px, or as SVG, from the QR Studio.
Limits
- Monthly code creation depends on your plan; resolution is never rate-limited.
- Lead form submissions are capped per code per minute to blunt spam.
- Uploads are capped at 2 MB for CSV import.