> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Short links, landing pages, and the publish lifecycle

> The two trackable artifact families on the links surface — a short link as one redirect record, a landing page as a renderable block tree — and the draft → publish → archive lifecycle that gates a page's public address, the role model behind both, and how public short links differ from private click-tracking on campaigns.

# 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](/guides/short-links-and-click-tracking) and the [short links cookbook](/guides/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 on `GET /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 ambiguous `0/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](/guides/short-links-and-click-tracking) §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`.

## 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 is `draft → published → archived`, with archive and draft reversible via `PATCH`:

* A page is created as `draft` by `POST /links/landing-pages`.
* `POST /links/landing-pages/:id/publish` gates on a non-empty block list (422 otherwise), mints the page's short link, and flips status to `published` with `short_url` populated.
* 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.
* `PATCH` can move a page between `draft` and `archived`; 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 to `owner`, `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](/numbers/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.

## The operator loop

In practice the loop runs: create a draft page, attach it to a campaign, publish (its `short_url` goes live), embed the short URL in sends or hand it to channels directly, read `links/:id/stats` or the campaign rollup, patch the blocks, republish (the short URL stays stable), and iterate. The [short links cookbook](/guides/short-links-cookbook) runs the publish step end to end; the [click-tracking guide](/guides/short-links-and-click-tracking) covers the analytics readings; the [API reference](/api-reference/links) holds the field shapes.
