#What this API solves
Most QR projects fail on the details: wrong format for print, unreadable colors, no landing, zero tracking. Our suite covers the full funnel: image generation → mobile page (“experience”) → scan/event logging.
#Endpoints & when to use them
#POST /v1/qr-code/generate — Render a QR image
- Best for: You already have a target URL/text and only need an image (SVG/PNG/JPG).
- Inputs:
qr_code_text+ styling (colors, eye/body styles, logo, frame), output controls (save,download,include_bytes). - Output:
mime,ext,width/height,file_url/file_path(when saved), optionaldata_base64, plus ametamap describing styling. - Format tip: Use
SVGfor print (infinite scale). UsePNGwith frames/logos for digital flyers.
#POST /v1/qr-experience/generate — Create a mobile “experience” + QR
- Best for: No website? Need a campaign page? Pass
typeand content; we build the page and generate the QR pointing to it. - Types:
page(Page Builder JSON),url,text,rating,mp3,pdf,social,images,app,videos,event(with calendar),coupon,feedback,vcard_plus. - Output:
scan_url(public),experience(id/code/type/title), and the same QR image payload as the generator. - Why it matters: You control the full UX post-scan, can update content later, and track scans + custom actions.
#POST /v1/qr-scan/scan — Log a scan
- Best for: Server-side logging when your scan route is hit (we also auto-log from our hosted routes).
- Identify experience via:
experience_idor pairtype+code. - Output:
ok,experience_id,code,type.
#POST /v1/qr-scan/event — Log a custom event
- Best for: Button clicks (
cta_click), ratings submitted, downloads, etc., tied back to an experience. - Inputs: experience (id or type+code),
event(string), optionalvalue, optionalmeta. - Output:
ok.
#Quick start
# 1) Plain QR image (SVG; best for print)
curl -sX POST "https://api.yeb.to/v1/qr-code/generate" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{ "api_key":"<YOUR_KEY>", "qr_code_text":"https://example.com/summer-menu", "image_format":"SVG" }'
# 2) Experience page + QR (gallery landing with CTA)
curl -sX POST "https://api.yeb.to/v1/qr-experience/generate" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{ "api_key":"<YOUR_KEY>", "type":"page",
"page":{ "version":1, "theme":{"primary":"#0ea5e9","accent":"#111111"},
"layout":{"cols":2,"gap":12},
"blocks":[
{"type":"hero","props":{"headline":"Winter Lookbook","description":"Short intro…","align":"center",
"cta":{"label":"SHOP NOW","href":"https://example.com"}}},
{"type":"gallery","props":{"scroll":"horizontal","images":[
{"url":"https://picsum.photos/seed/a/600/400"},{"url":"https://picsum.photos/seed/b/600/400"}]}},
{"type":"button","props":{"label":"Open site","href":"https://yeb.to","variant":"primary","align":"center"}}
]},
"image_format":"PNG","image_width":600,
"qr_code_logo":"scan-me","frame_name":"bottom-banner","frame_text":"Scan me",
"save":1,"storage_disk":"public","storage_folder":"qr_codes","filename_base":"winter-lookbook" }'
# 3) Log a custom event (CTA click)
curl -sX POST "https://api.yeb.to/v1/qr-scan/event" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{ "api_key":"<YOUR_KEY>", "type":"page", "code":"<experience_code>",
"event":"cta_click", "value":"shop_now", "meta":{"source":"landing"}}'
#Full “everything on” request (covers most options)
Use this to see how fields combine. Trim what you don’t need.
POST /v1/qr-experience/generate
{
"api_key": "YOUR_KEY",
"type": "page",
"image_format": "PNG",
"image_width": 720,
"foreground_color": "#111111",
"background_color": "#FFFFFF",
"body_style": "dot",
"eye_style": "circle",
"eye_outer_color": "#111111",
"eye_inner_color": "#111111",
"eye1_outer_color": "#111111",
"eye1_inner_color": "#FF4D4D",
"eye2_outer_color": "#111111",
"eye2_inner_color": "#FFB84D",
"eye3_outer_color": "#111111",
"eye3_inner_color": "#4DD2FF",
"qr_code_logo": "scan-me",
"frame_name": "bottom-banner",
"frame_color": "#111111",
"frame_text": "Scan me",
"frame_text_color": "#FFFFFF",
"frame_icon_name": "qr",
"save": 1,
"download": 0,
"include_bytes": 0,
"storage_disk": "public",
"storage_folder": "qr_codes",
"filename_base": "campaign-q1",
"page": {
"version": 1,
"theme": { "primary": "#0ea5e9", "accent": "#111111" },
"layout": {
"cols": 2, "gap": 12,
"sections": { "enabled": false, "collapsible": false, "default_open": true,
"style": "card", "radius": 12, "border": "1px solid rgba(255,255,255,.12)", "background": "rgba(255,255,255,.03)" }
},
"blocks": [
{ "type": "hero", "props": { "headline": "Winter Lookbook", "description": "Short intro…", "align": "center",
"cta": { "label": "SHOP NOW", "href": "https://example.com?utm_source=qr&utm_campaign=winter" } } },
{ "type": "gallery", "props": { "scroll": "horizontal", "images": [
{ "url": "https://picsum.photos/seed/a/600/400" }, { "url": "https://picsum.photos/seed/b/600/400" } ] } },
{ "type": "video", "props": { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" } },
{ "type": "pdf", "props": { "url": "https://example.com/catalog.pdf", "title": "Catalog" } },
{ "type": "appBadges", "props": { "ios":"https://apps.apple.com/app/id000000", "android":"https://play.google.com/store/apps/details?id=app" } },
{ "type": "socialLinks", "props": { "items":[
{"name":"Instagram","url":"https://instagram.com/brand"},{"name":"TikTok","url":"https://tiktok.com/@brand"} ] } },
{ "type": "button", "props": { "label":"Open site", "href":"https://yeb.to", "variant":"primary", "align":"center" } }
]
}
}
#Parameters that actually matter
Image generation
| Param | Type | Required | Why it matters |
|---|---|---|---|
qr_code_text | string | Yes (generator) | The content to encode. For experiences we auto-use scan_url. |
image_format | SVG|PNG|JPG | No | SVG for print; PNG for most branded/all-color cases; JPG is smallest but lossy. |
foreground_color/background_color | #RRGGBB | No | Ensure 40%+ contrast. Avoid light-on-light; scanners fail. |
body_style/eye_style | string | No | “dot” body + “circle” eyes feels modern; keep eyes visible for reliability. |
qr_code_logo | enum | No | “scan-me” boosts intent. For uploads, ensure 15–20% center area only. |
frame_name + text/icon | enum | No | Frames add CTA without redesigning posters; great for flyers/menus. |
save/download/include_bytes | 0|1 | No | save=1 returns file_url. download=1 triggers file response; we auto-force bytes. Default bytes: 1, but 0 if save=1 to keep payloads light. |
Experience generation
| Param | Type | Required | Practical guidance |
|---|---|---|---|
type | enum | Yes | Pick the smallest that solves your flow. page is the most flexible. |
page.version | int | Yes (page) | Schema version; current UI uses 1. |
page.blocks[] | array | Yes (page) | Hero, gallery, video, mp3, pdf, socialLinks, event, coupon, rating, feedback, vcardPlus, text, button, spacer, divider. |
event.* | mixed | Yes (event) | Automatically generates an .ics file; perfect for meetups/concerts. |
vcard_plus.* | mixed | Yes (vcard_plus) | Generates a downloadable .vcf and optional photo avatar. |
Scan & events
| Param | Type | Required | Notes |
|---|---|---|---|
experience_id OR type+code | int / string | Yes | Either pass the numeric id or the pair; avoid both. |
event | string | Yes (for /event) | Example: cta_click, rating_submitted, download. |
value | string|number | No | Optional payload (e.g., rating value, button id). |
meta | object | No | Extra attribution (campaign, placement). IP/UA/referrer are auto-recorded server-side. |
#Reading & acting on responses
QR image (generator)
{
"mime":"image/png","ext":"png","width":720,"height":880,
"saved":true,"file_url":"https://cdn.your-site/qr_codes/2025/08/21/qr-...png",
"file_path":"qr_codes/2025/08/21/qr-...png",
"meta":{"format":"PNG","logo":"scan-me","shape":{"body":"dot","eye":"circle"}},
"data_base64": null
}
- Store
file_urlfor reuse. Keepmetaif you render previews. - Large payloads? Set
include_bytes=0and rely on CDN URLs.
Experience + QR
{
"scan_url":"https://yeb.to/s/abc123",
"experience":{"id":1902,"code":"abc123","type":"page","title":"Winter Lookbook"},
"mime":"image/png","ext":"png","width":720,"height":880,
"saved":true,"file_url":"https://.../qr_codes/.../campaign-q1.png",
"meta":{ "...": "..." }, "data_base64": null
}
scan_urlis the URL to print/embed into any QR.- Use
qr-scan/eventto track CTA clicks (e.g., “Get tickets”).
#Practical recipes
- Print-ready assets: Prefer
SVG. Keep a 4-module quiet zone; test from 30–50 cm. - Brand triad: Per-eye inner colors (
eye1/2/3_inner_color) for brand palettes without hurting readability. - Events/RSVP:
type=eventauto-generates.ics; add a CTA to a ticketing URL. - vCard at conferences:
type=vcard_plusproduces a downloadable contact card + avatar. - Attribution: Append
?utm_source=qrto external links inside page blocks; also log/eventon click.
#Errors & safeguards
422— Validation (e.g.,page.blocksmissing fortype=page).404— Experience not found (wrongtype/codepair).410— Experience inactive/expired.download=1forces raw bytes; prefersave=1+ CDN for production.
#API Changelog (QR Suite)
qr-experience/generate and QR styling options.
event now supports cover images; feedback adds display=wizard and cover support.
/v1/qr-scan/scan and /v1/qr-scan/event for server-side tracking with IP/UA/referrer capture.
include_bytes defaults to 0 when save=1; frames and logos documented in meta.
type=page) with blocks (hero, gallery, video, mp3, pdf, socialLinks, event, coupon, rating, feedback, vcardPlus, text, button, spacer, divider).
Use the endpoint playgrounds on this page to test payloads and lock in your defaults (format, logo/frame, storage path).