Skip to main content

Landing pages

The landing-page builder turns a campaign link destination into something you own: a mobile-first microsite assembled from blocks, published to a trackable short link, with every visit and conversion attributed back to the message and campaign that sent it. No code, no external hosting, no third-party page tool — the page, its short link, and its analytics all live on the same /links surface you already use. For request and response schemas, see the links API reference. For the click-quality pipeline the short link inherits, see short links with click tracking.

1. What the builder is for

SMS and WhatsApp bodies travel plain — a long URL at the end of a message converts worse than a focused destination page, and every character costs segments. The builder gives a campaign a rich destination without standing up infrastructure:
  • A mobile landing page for a campaign — headline, offer, opt-in form, coupon.
  • A link-in-bio microsite published once, then dropped into any SMS, WhatsApp, or RCS message.
  • A conversion surface — a recipient’s opt-in submit, coupon claim, or CTA click is recorded as a conversion event attributed to the exact message they came from.
Pages render server-side as a single self-contained HTML document with no client-side JavaScript, and every operator-supplied string is HTML-escaped, so a page definition cannot inject markup or script into a recipient’s browser.

2. Create a page in the dashboard

Open Messages → Landing Pages in the dashboard and click New landing page. Give the page a title, optionally a slug (a short, URL-safe label; when omitted, the slug is derived from the title), and define the page content. Every new page starts in draft — it has no public URL yet and nothing is visible to recipients. Drafts are safe to save and iterate on: the block list can be empty while you assemble the page, and nothing about a draft is reachable from outside your tenant. The same create operation is available over the API:
cURL
Response:
If the slug you asked for is already taken, it gets a short suffix so the create still succeeds — the response carries the resolved value. Edit the page at any time with PATCH /api/v1/links/landing-pages/:id. Every field is optional; updates work for drafts and published pages alike, and a published page keeps its existing short link while its content changes. Set "status": "archived" on the same call to retire a page without deleting its history. List everything (optionally filtered by status) with GET /api/v1/links/landing-pages.

3. The block library and the content model

A page is a list of blocks. The builder’s model stores exactly one theme (optional accent and background colors, hex literals like #325FEC) plus up to 50 blocks, each one of four types: Two validation levels apply. On create and update the content is lenient — an empty block list is a legal work-in-progress draft, and a malformed block answers a 422 naming the field. At publish the strict level applies: the page must contain at least one block. Dashboard cards show each page’s live visits and conversions counters; the API row carries the same counts alongside status (draft, published, archived), short_code, and the campaign attribution. Publishing is one call:
cURL
Response:
Publishing mints a standard 6-character short code on the same shortener that powers POST /api/v1/links — so the page’s short_url respects your branded short domain and inherits the full click pipeline: per-IP rate limiting, bot-vs-human click scoring, per-contact click history, and the short_link.click webhook. The short link redirects to the page itself, and any click attribution you have already configured for plain short links covers landing-page traffic with no extra wiring. Publish is idempotent. Calling it again on a published page returns the existing short link — no new code is minted. Update the content and call publish again and the same short URL keeps working. Drop the short URL into any message — SMS, WhatsApp, RCS — as the campaign destination. Because it is a standard tracked link, click-through reporting on the message plays against the same funnel you already read.

5. Analytics: visits and conversions per page

Every page aggregates two counters: a visit (a recipient opening the page) and a conversion (an opt-in form submit, a coupon claim, or a CTA click). Read the rollup over the API:
cURL
Response:
In the dashboard, click Analytics on any page card to read the same totals plus the per-campaign breakdown. top_limit (1–50, default 10) bounds the by_campaign, by_message, and recent_conversions sections. A conversion event records its kind, the sending campaign and message, the converting contact when known, and a value (the submitted email, the claimed coupon code). Aggregation is bounded — up to 50,000 recent events per page feed the rollup — so analytics stay fast on high-traffic pages.

6. Feeding campaign ROAS attribution

Attribution rides the events themselves: { campaign, message, contact } is stamped on every recorded visit and conversion, so by_campaign and by_message answer “which sends drove page activity” without any join work on your side. The per-page rollup slots into campaign ROAS reporting on the engagement rung of the funnel — a page visit is the downstream of the message’s tracked click, and a conversion is the measurable action the campaign paid for. Send the page’s short link through a campaign and the campaign’s attribution panel picks up the same events alongside its tracked clicks and conversions. See campaign ROAS and revenue attribution for how attributed revenue, send cost, and ROAS are computed.

7. Roles: who can create, publish, and delete

The write operations — create, update, publish, delete — are restricted to owner, admin, and developer roles, on both the API and the dashboard. Other roles, including viewers, can list pages and read analytics but cannot create, publish, edit, or delete them. A caller outside the write roles gets a 403 on write calls. The dashboard page applies the same guard, so what you see matches what the API would let you do.

8. Troubleshooting

Delete a page with DELETE /api/v1/links/landing-pages/:id (204 on success) when it is truly done — its visit and conversion events are removed with it. To keep the history, archive the page instead via PATCH with "status": "archived".