Concepts
Page content
Page codes host a mobile page at their short link. The content object on create and update sets what the page shows. Two fields work on every type: title (string, max 120) and accent (hex color like #7c3aed, the page's highlight color).
How normalization works#
The API normalizes content instead of rejecting it: unknown fields are dropped, over-length strings are truncated, URL fields accept http(s) only and store empty otherwise, and dates outside YYYY-MM-DD store empty. The request still succeeds, so open the hosted page (or GET the code) after your first integration test and check the result.
links#
A link-in-bio page.
| tagline | the bio; string, max 240, line breaks kept |
| links | array of { label (max 80), url }, max 50; rows missing either are dropped. url may be a web address, an email address (stored as mailto:) or tel:+number. Each web address must pass the safety check, else 422 unsafe_destination |
| links[].kind | "heading" makes the entry a label between groups of links (no url) |
| links[].emoji / hidden / featured | one emoji shown on the button; boolean to keep it off the page; boolean to make it stand out |
| socials | object of profile links shown as icons: instagram, tiktok, youtube, facebook, x, linkedin, whatsapp, email, website. Handles (@name) and a WhatsApp number with country code are accepted |
| theme | light (default), dark or color. Dark and color show on Starter and above |
| buttonStyle / buttonShape | fill | outline | soft, and rounded | pill | square. Non-default values show on Starter and above |
| photo and banner | upload-only (dashboard); an edit through the API keeps them |
menu#
A restaurant menu with sections and priced items.
| tagline | string, max 160 |
| theme | light (default), dark or photo. Dark and photo show on Starter and above |
| currency | string, max 8, default $ |
| sections | array of { name (max 80), desc (max 200), icon (one emoji), hidden (boolean), items }, max 20; unnamed sections are dropped |
| sections[].items | array of { name (max 80), price (max 20), desc (max 160) }, max 50 per section and 200 per menu |
| items[].variants | array of { label (max 40), price (max 20) }, max 6; shown instead of price |
| items[].tags | any of: vegetarian, vegan, spicy, gluten-free, halal, new, popular |
| items[].soldOut | boolean; the item stays on the page, greyed |
| languages | array of language codes, first is the default (en, si, ta, hi, zh, ja, ko, fr, de, es, it, pt, ru). One language shows below Pro, three on Pro, all on Business |
| i18n | translations for the other languages: { si: { title, tagline, hours, note } }. Sections and items take the same shape with { name, desc }. Anything missing falls back to the default language |
| hours / note | string, max 400 / 300; line breaks are kept |
| phone / email / address | string, max 40 / 120 / 200 |
| website / googleReviewUrl / tripadvisorUrl | URL; a bare domain is accepted and stored as https://… |
| instagram / facebook / tiktok | URL or @handle |
| wa.me URL, or a number with + and country code | |
| whatsappOrders | boolean; scanners can build an order on the page and send it to the whatsapp number. Needs whatsapp to be a number |
| photos, cover and logo | upload-only (dashboard). Editing a menu keeps them: each section and item keeps the photos of the entry with the same name, or the same position if it was renamed. Everything else is replaced by what you send: omit tags or translations and they are cleared |
vcard#
A digital business card (vCard Plus) with a Save contact button that downloads a .vcf.
| firstName / lastName | string, max 60 each |
| pronouns | string, max 30; shown next to the name, not saved with the contact |
| jobTitle / org | string, max 80 each |
| bio | string, max 500, line breaks kept |
| phones | array of { type: mobile | work | home | other, number }, max 4. Every number must start with + and the country code (e.g. +15550001234), else 422 invalid_phone |
| emails | array of { type: work | personal | other, address }, max 3; invalid addresses are dropped |
| website | URL; a bare domain is accepted. Must pass the safety check, else 422 unsafe_destination |
| address | string, max 300, line breaks kept; shown with a Directions link |
| socials | object of profile links: linkedin, instagram, x, facebook, tiktok, youtube, whatsapp. Handles (@name) are accepted |
| theme | light (default) or dark |
| phone / email / note | the older single-field shape; still accepted (note becomes bio) |
| photo and banner | upload-only (dashboard); an edit through the API keeps them. The photo is embedded in the downloaded .vcf |
video#
A page of YouTube or Vimeo videos.
| tagline | the line under the name; string, max 300, line breaks kept |
| videos | array of { url, title (max 120), desc (max 600), hidden (boolean) }, max 12. url must be a YouTube or Vimeo video link (Shorts and unlisted videos work), else 422 invalid_video. The first is shown large. title is optional: the video's own title and channel are looked up from YouTube or Vimeo when you save |
| buttons | array of { label (max 60), url }, max 3; rows missing either are dropped. url may be a web address, an email address or tel:+number, and must pass the safety check, else 422 unsafe_destination |
| socials | object of profile links shown as icons, as for links |
| theme | light (default) or dark |
| videoUrl / description | the older one-video shape; still accepted and stored as a page with that one video |
| logo | upload-only (dashboard); an edit through the API keeps it |
coupon#
A coupon: the offer, a code with Copy, an optional barcode or QR code for the till, and the dates it is valid.
| discount / title / business | string, max 120 / 120 / 100; discount is the headline (20% off) |
| description / terms | string, max 1000 / 2000, line breaks kept |
| code | string, max 40 |
| barcode | none (default), code128 or qr. code128 holds printable ASCII only, else 422 invalid_coupon |
| validFrom / validUntil | YYYY-MM-DD, inclusive whole days; anything else is 422 invalid_coupon |
| timezone | IANA zone the days start and end in, e.g. Europe/London |
| address | string, max 300; shown with Directions |
| buttons | array of { label (max 40), url }, max 2; hidden once the offer has ended. Must pass the safety check |
| socials / theme | profile links as for links; light (default) or dark |
| ctaUrl / ctaLabel | the older one-button shape; still accepted |
| logo and banner | upload-only (dashboard); an edit through the API keeps them |
apps#
An app download page. Visitors see their own store first; phones can be sent straight to it.
| title / developer / tagline | string, max 80 / 80 / 120 |
| description | string, max 1500, line breaks kept |
| stores | object of store links: ios (apps.apple.com), testflight (testflight.apple.com/join/…, a beta invite), android (play.google.com), huawei (appgallery.huawei.com), amazon (amazon.*), microsoft (apps.microsoft.com). A link to the wrong store is 422 invalid_store_link |
| website | URL of a web version or the app's site |
| autoRedirect | boolean; an iPhone scan opens the App Store and an Android scan Google Play, without the page |
| features | array of strings, max 6, max 100 each |
| socials | profile links, as for links |
| theme | light (default) or dark |
| iosUrl / androidUrl / fallbackUrl | the older shape; still accepted |
| icon and screenshots | upload-only (dashboard); an edit through the API keeps them |
event#
An event page with a countdown, Add to calendar, venue and online link, buttons, schedule and speakers.
| tagline | string, max 160 |
| description | string, max 2000, line breaks kept |
| startDate / endDate | YYYY-MM-DD; endDate only for an event over several days. Anything else is 422 invalid_event |
| startTime / endTime | 24-hour HH:MM; omit startTime for an all-day event |
| timezone | IANA zone the times are in, e.g. Europe/London. Needed for the countdown and calendar entries to be right everywhere |
| mode | in_person (default), online or hybrid |
| venue / address | string, max 120 / 300; the address keeps line breaks |
| onlineUrl | URL for an online or hybrid event; must pass the safety check |
| buttons | array of { label (max 40), url }, max 3; hidden once the event is over. Must pass the safety check, else 422 unsafe_destination |
| agenda | array of { date (multi-day events), time, title (max 100), desc (max 160) }, max 30 |
| speakers | array of { name (max 80), role (max 100) }, max 12. Photos are upload-only; an edit keeps a speaker's photo by name |
| organizer / socials | string, max 100; profile links as for links |
| theme | light (default) or dark |
| date / time / ctaUrl / ctaLabel | the older shape; still accepted |
business#
A business page: open-now status from weekly hours, quick actions, about, amenities, photos and buttons.
| title / tagline / description | string, max 120 / 160 / 2000 |
| phone / email / website / address | contact details; the address keeps line breaks and is shown with Directions |
| hoursMode | weekly, always (open 24/7) or none (default) |
| week | 7 arrays of { from, to } as HH:MM, Sunday first, up to 2 per day; an empty day is closed; to earlier than from runs past midnight. Anything else is 422 invalid_hours |
| timezone | IANA zone the hours are in, e.g. Europe/London; required with weekly hours |
| hoursNote | string, max 400, e.g. Closed on public holidays |
| amenities | any of: wifi, parking, wheelchair, cards, delivery, takeaway, outdoor, pets, kids, aircon |
| buttons | array of { label (max 40), url }, max 3. Must pass the safety check |
| socials / theme | profile links as for links (whatsapp becomes a quick action); light (default) or dark |
| hours / ctaUrl / ctaLabel | the older shape; still accepted (hours becomes hoursNote) |
| logo, banner and photos | upload-only (dashboard); an edit through the API keeps them |
feedback#
A feedback page: a rating (stars or faces), optional topics, a comment and an optional contact for a reply. Every visitor is then offered your public review links.
| title | the business's name |
| question | string, max 200, default How was your experience? |
| ratingStyle | stars (default) or faces |
| aspects | array of { label (max 40) }, max 5: topics rated on their own |
| commentPrompt / thanksMessage | string, max 160 / 300 |
| askContact | boolean; offer a field for an email or phone, for a reply |
| reviews | object of review page links: google, tripadvisor, facebook, yelp, trustpilot. Shown to every visitor after sending. Must pass the safety check |
| buttons | array of { label (max 40), url }, max 2, on the thank-you screen |
| notifyLow | boolean; email the account owner about 1 and 2 star responses (at most 10 a day) |
| theme | light (default) or dark |
| logo | upload-only (dashboard); an edit through the API keeps it |
social#
One page of profiles, in order. Each link must be on its network's own site.
| about | string, max 300; line breaks kept |
| profiles | array of { network, url, label }, max 20. network: instagram, tiktok, youtube, facebook, x, linkedin, threads, pinterest, snapchat, whatsapp, telegram, spotify, twitch, discord, email or website. url: a link on that network, or a handle ("@name") where the network has them; a phone number with its country code for whatsapp; an address for email. label: optional, max 60, shown instead of the network's name. A link that is not on its network is 422 invalid_profile |
| theme / iconStyle | light or dark / brand (each network's colours) or accent (the page's colour) |
| instagram / facebook / x / tiktok / youtube / linkedin / whatsapp / website | the older shape, one field per network; still accepted and turned into profiles |
| avatar | upload-only (dashboard); an edit through the API keeps it |
gallery#
A photo album with a full-screen viewer. Photos upload in the dashboard; an edit through the API keeps them.
| description | string, max 1000; line breaks kept |
| layout | grid (default), feed (full width, one under another) or slides. Anything else is 422 invalid_layout |
| theme | light (default) or dark. Anything else is 422 invalid_theme |
| downloads | boolean; show a Save button on each photo in the viewer. Not a boolean is 422 invalid_downloads |
| buttons | array of { label (max 40), url }, max 2, under the photos. Must pass the safety check |
| images | upload-only (dashboard). On an edit, send [{ id, caption }] to change captions (max 200) of photos already on the page; other fields are ignored |
audio#
An MP3 page: cover art, a player and a track list. Tracks and the cover upload in the dashboard; an edit through the API keeps them.
| artist | string, max 120; the artist, band or host shown under the title |
| description | string, max 1000; line breaks kept |
| listen | object of streaming links: spotify, appleMusic, youtubeMusic, soundcloud, bandcamp, amazonMusic. Each must be on that service's own site. An unknown service or a link elsewhere is 422 invalid_listen_link |
| buttons | array of { label (max 40), url }, max 3, under the player. Must pass the safety check |
| downloads | boolean; show a download button on each track. Default false |
| theme | light (default) or dark. Anything else is 422 invalid_theme |
| tracks / coverFileId | upload-only (dashboard): MP3, M4A or WAV, up to 20 MB each, 20 per page |
tag#
A lost-and-found page for a pet tag or an item label. The photo uploads in the dashboard; an edit through the API keeps it.
| kind | pet (default) or item. Anything else is 422 invalid_kind |
| name / owner | strings, max 80 each: the pet's name or what the item is, and the owner's name as finders see it |
| message / lostNote | strings, max 400 each; line breaks kept. lostNote shows while lost is true |
| lost | boolean; lost mode turns the page red and leads with lostNote. Not a boolean is 422 invalid_lost |
| phone | international format with the country code, e.g. +1 555 000 1234. Otherwise 422 invalid_phone |
| boolean, default true; offer WhatsApp on the same number | |
| an email address. Otherwise 422 invalid_email | |
| details | array of { label (max 40), value (max 200) }, max 6 |
| photoFileId | upload-only (dashboard) |