Short links, landing pages, and the publish lifecycle
Orbit’s links surface (/api/v1/links) offers two trackable artifact families and one lifecycle that joins them. The guides — short links with click tracking and the short links cookbook — show you the how-to; this page names the model those guides operate on, so you know what a short link is versus a landing page, why a page has no public address until publish, and who can do what.
Two artifact families
A short link is one redirect record: an id, a 6-character code, and the original URL it points to. Clicks onGET /l/:code resolve the code to the original URL and record attribution — the originating message, the campaign, and the identifying session signals (IP, user-agent, referrer).
A landing page is a renderable content block tree published under a short code. The draft holds an ordered list of blocks (hero / product_grid / opt_in_form / coupon), constrained to http(s) URLs and HTML-escaped strings so a page definition can’t inject markup. Publishing renders the tree into the public document served at GET /lp/:code.
Both families share the same public address path GET /l/:code, so they draw the same click pipeline — per-link stats, per-campaign rollup, per-contact attribution, and the short_link.click webhook.
The short-link model
A short link is created by minting a code with no colliding predecessor. The code is drawn by rejection sampling over a 56-character alphabet (no ambiguous0/O/1/I/l), so ~41 of every 100 random 6-character strings are safe codes. The service re-tries on collision a handful of times before refusing.
The public face is the root-mounted GET /l/:code redirect — anonymous, per-IP rate-limited, mounted directly on the API host (not under /api/v1), so it stays reachable after the X-API-Key middleware rejects unauthenticated /api/v1 traffic. Each click runs the click pipeline: a raw click row, quality scoring against a bot user-agent list, country from the edge CDN geo header, then fan-out to per-link stats, per-contact click history, and GET /campaigns/:campaignId/link-analytics — the SMS link-tracking + attribution rollup for the campaign the link belongs to (see the click-tracking guide §6).
Per-campaign attribution lives on the row as campaign_id (set at mint) and message_id (set when the send pipeline mints inline). A link with no campaign_id drifts out of the campaign rollup but still counts tenant-wide at GET /links/insights.
Branded short-link domains
By default, minted short links live on the platform host. Your tenant can override the host with its own vanity domain, so recipients see your brand in the URL instead of the platform’s. Set it in the dashboard under Settings → General → Branded short-link domain. The value is stored on your organization’s settings asshort_link_domain and read every time a short link is minted, so outbound SMS/WhatsApp sends pick it up automatically — no per-campaign configuration.
The setting accepts a bare host only:
http://orhttps://scheme, with a resolvable host (use https in production)- No path, query, or fragment — Orbit appends
/l/<code>itself - At most 256 characters
- A trailing slash is stripped silently
GET /l/:code always looks the code up in the same record, regardless of which host served the URL.
The landing-page model
A landing page’s draft content is validated against a lenient schema (the block list may be empty) so a work-in-progress page can be saved. Publish re-validates against the strict publish schema — at least one block — so a page with no renderable content can never go live. The transition mints a short link whose target is the internal render path (/lp/:code), then stamps status: "published" alongside the short_code and short_link_id. Publish is idempotent: re-publishing an already-published page returns the page as-is with its live short URL, rather than minting a new code. The pair of guards (publish requires renderable content; republish returns as-is) is what keeps the short code stable while you iterate on blocks.
Publication semantics
The lifecycle isdraft → published → archived, with archive and draft reversible via PATCH:
- A page is created as
draftbyPOST /links/landing-pages. POST /links/landing-pages/:id/publishgates on a non-empty block list (422 otherwise), mints the page’s short link, and flips status topublishedwithshort_urlpopulated.- Republishing flips nothing new: the call returns the existing published page as-is. Re-minting is explicitly avoided so a legitimate not-found never triggers a spurious new code.
PATCHcan move a page betweendraftandarchived; archived pages stop appearing in pickers but retain their history.- Visits and conversions roll up per page at
GET /links/landing-pages/:id/analytics, broken down by campaign and by originating message.
Roles and access
Write operations on both families — creating or publishing a landing page, minting a one-off short link, deleting either — are gated toowner, admin, and developer. Reads (list, get, stats, analytics) are open to any authenticated caller. The public redirect and render endpoints carry no role check at all — they serve the recipient, not the operator. This shape means a marketer with read access can study a page’s analytics while only an owner/admin/developer pushes the page live.
Public short links vs. private click-tracking
Contrast with number masking — proxy sessions exist to hide two parties’ identities from each other; a short link’s purpose is to expose click intent. The privacy surface (number masking) forwards traffic through a shared proxy number so neither side sees the other’s real address. The click surface (short links, landing pages) intentionally records who clicked, when, and from where, so campaign attribution and contact engagement history work. Both exist on the same platform; the distinction is which one you want when.Tracked deep links
A tracked deep link is a short link minted for app-bound destinations rather than plain web pages. When an RCS rich message carries a suggested action that should open your app, Orbit mints short links for both the deep link and its web fallback, so a tap on either surface — a capable device opening the app, or a downgraded one opening the browser — resolves through the sameGET /l/:code redirect, records the click with its originating message and campaign, and lands on your real target. This is the builder behind Verify’s OTP autofill suggestion.
One exception: a verified app link (Android App Links / iOS Universal Links) is passed through untouched. The OS only honors an app-link association on your own registered domain, so rewriting it through the redirect host would break the association; those URLs are never minted. Everything else about tracked deep links is the same model as web short links — same code shape, same click pipeline, same attribution and stats surfaces.
Limits
- Public redirect —
GET /l/:codeis rate-limited per IP address to 60 requests per minute. A recipient hitting the cap gets a 429, not a redirect, until the window resets; the limit is scoped to the redirect route and does not affect authenticated API traffic. - Code minting — codes are 6 characters drawn from a 56-character unambiguous alphabet (no
0/O/1/I/l) using rejection sampling from random bytes, so every code is unbiased. On the astronomically rare collision with an existing code, the mint retries with a fresh code a handful of times before refusing. - Auto-shorten threshold — the SMS auto-shorten path only replaces URLs longer than 30 characters, and never swaps in a minted link that is not strictly shorter than the original, so shortening can never lengthen a message body.
The operator loop
In practice the loop runs: create a draft page, attach it to a campaign, publish (itsshort_url goes live), embed the short URL in sends or hand it to channels directly, read the analytics, patch the blocks, republish (the short URL stays stable), and iterate. The short links cookbook runs the publish step end to end; the click-tracking guide covers the analytics readings; the API reference holds the field shapes.
For the readings themselves, the dashboard’s Insights → Links page is the tenant-wide view. The header cards show total links, total clicks, unique visitors, and average clicks per link for the selected window, plus a “verified” set — raw counts filtered down to human clicks after bot, link-preview, and script signatures are excluded. Below that, the top links table ranks your most-clicked links and a per-day timeline charts the click trend. Opening a link drills into its recent clicks with timestamp, IP, user agent, referrer, and country. The page also carries the full link management table (create, copy, delete) and a CSV export of the current view, so day-to-day link hygiene lives in the same place as the analytics. For single-link checks, GET /links/:id/stats answers the same drill-down over the API.
See also
- QR code generation model — the untracked render counterpart: encode a short link’s public URL into a QR when a printed code needs click attribution.