Design a QR code
Pick one of 100 catalog presets or build a custom look — module and eye shape, color or gradient, background, logo, caption — with a live preview.
The look of a QR code is a small, validated JSON config. Only that config is stored — the SVG is rendered from it fresh every time, so the same config always produces the same code (a requirement for anything you're about to print). You can either point at one of the 100 built-in looks, or send your own config.
Use a catalog preset
curl https://app.tease.link/api/admin/qr/presets \
-H "Authorization: Bearer $TEASE_API_KEY"Returns 100 entries — 10 shape families (classic, rounded, dots, diamond, classy,
compact, brand, sticker, bold, sharp) crossed with 10 color palettes (mono, ink,
ofblue, insta, sunset, neon, gold, rose, ice, pink). Each entry's id
("<family>-<palette>", e.g. rounded-insta) is what you pass as preset when creating or
updating a code — the full design object is there too if you want to start from a preset and
tweak it.
Build a custom design
Send a design object instead of (or as a starting point layered over) a preset:
| Key | Type | Description |
|---|---|---|
module | string | Dark-module shape: square, rounded (neighbour-aware, so touching modules blend into one connected shape), dot, or diamond. |
eye_frame | string | Finder-eye frame: square, rounded, circle, or leaf. |
eye_dot | string | Finder-eye pupil: square, rounded, or circle. |
fg | string | Solid module color, #rrggbb. |
fg_grad | object | Gradient fill, wins over fg: { "kind": "linear" | "radial", "stops": [[0–1, "#hex"], …] }, 2–3 stops, plus an optional linear dir: [x1, y1, x2, y2] (fractions 0–1). |
eye_fg | string | Separate eye color; omit to reuse the module color/gradient. |
bg | string | Card background, #rrggbb or none for transparent. |
card_radius | int | Card corner radius, 0–80. |
logo | string | Center logo: "" (none), tease (the brand mark), or icon:<name> — any name from GET /api/admin/qr/logo-icons. Tint with logo_color, plate color with logo_bg (#rrggbb or none). |
caption | string | Text under the code (e.g. SCAN ME), up to 24 characters. Color via caption_color. |
Anything you don't set falls back to the engine default (dark rounded modules on white). Sending
an object with unknown keys, an out-of-range value, or a non-hex color returns 400 design_invalid with a message naming the offending field — nothing partial is ever saved.
Scannability is handled for you, not something to configure: error correction jumps to level H the moment a logo is set (the center cut-out stays inside the ~8% actual / 30% budget), and stays at level Q otherwise. The quiet zone is always 4 modules. You don't pick the error correction level directly.
Live preview while building
POST /api/admin/qr/render takes { "design": {...}, "url": "..." } and returns { "svg": "..." } — the same renderer the saved-code endpoint uses, so what you see is exactly what a scan of
the finished carrier will look like. Use it to iterate on a design before attaching it to a code
with preset/design on create or PATCH.
How to know it worked
The preview SVG renders without a design_invalid error, and a phone scan of the rendered code
resolves to the URL you passed. If you added a logo, check the preview at a small size too — a
busy custom-icon logo can still read badly even though the encoder guarantees it decodes.
If it didn't work
400 design_invalid— the error message names the exact key. Check it against the table above; a common one is alogovalue that isn't"",tease, oricon:<name>for a nameGET /api/admin/qr/logo-iconsactually lists.404 preset_not_found— the preset id doesn't match"<family>-<palette>"fromGET /api/admin/qr/presets; ids are case-sensitive.- Render succeeds but an already-saved code 500s instead — that's a removed icon file, not a bad config; see Troubleshooting.
What's next
- Create a QR code for print — attach the design to a new code.
- Download a code for print — get the finished file.