> ## 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 link not resolving or LINK_NOT_FOUND

> Diagnose a short-link redirect that returns a branded 400 or 404, or a landing-page conversion that returns LINK_NOT_FOUND, without retrying a deterministic lookup miss.

# Short link not resolving or `LINK_NOT_FOUND`

Use this runbook when a short link does not open, or when a landing-page conversion
request returns `404 LINK_NOT_FOUND`. Orbit has two related public surfaces:

* `GET /l/:code` looks up a short code and redirects a visitor to its stored target.
* `POST /public/lp/:code/convert` records a conversion for the published landing
  page represented by that code.

The code lookup is deterministic. An unknown, expired, or unpublished code does
not become valid after a retry, and Orbit intentionally uses the same not-found
outcome for those cases.

## Split the symptom first

### A. The redirect shows a branded 400 or 404 page

You minted a link, but opening its `/l/:code` URL returns a 400 or 404 instead
of the target page. Check the exact code and the host in the URL. The redirect
may be using the platform host or your tenant's branded short-link host.

Browser agents receive a self-contained branded HTML error page. It is `noindex`,
does not track the request, and does not echo the raw code. That page is expected
for a browser request when the lookup misses or the stored target fails its
safety check. API clients receive the canonical JSON error envelope instead.

### B. Conversion returns `404 LINK_NOT_FOUND`

Your landing page calls `POST /public/lp/:code/convert`, but the response has
`LINK_NOT_FOUND`. This endpoint accepts only a code for a **published** landing
page. Unknown, expired, and unpublished codes all collapse to this same 404 so
the public endpoint does not reveal page state.

`LINK_NOT_FOUND` is not a signal to mint a replacement during the conversion
request. Confirm the page's publication state with your authenticated tenant
controls, then update the page or re-mint the public link before trying the
conversion again.

## Causes and fixes

| Cause | What you will see | Fix |
| - | - | - |
| Unknown code | `GET /l/:code` returns 400/404, or conversion returns `404 LINK_NOT_FOUND`. The code is absent from your tenant's link or landing-page records. | Verify the complete code copied into the URL. If it is absent, mint a new link or use the published page's current short URL. |
| Expired code | The code used to work, then moved into the same 404-alike bucket. | Check the link's expiry in the authenticated links view. Re-mint the link and replace it everywhere it was shared. |
| Unpublished landing page | Conversion returns `LINK_NOT_FOUND`; the page is still `draft` or no longer `published`. | Publish the page, then use its published short URL. Do not call conversion against a draft code. |
| Stored target is no longer an HTTP(S) URL | The redirect returns the same branded 400/404-style page even though the code exists. | Restore the target through the authenticated links controls only if it is a valid `http://` or `https://` URL. Otherwise, mint a new link. Orbit refuses a tampered non-HTTP(S) target at redirect time. |
| Invalid target at mint time | `POST /api/v1/links` returns `422 VALIDATION_ERROR`. The URL is missing, has an invalid shape, or uses a protocol such as `javascript:` or `data:`. | Send a correctly formed absolute `http://` or `https://` URL, then mint again. |
| Per-write rate limit | Link minting returns a rate-limit response after more than 20 requests per minute. | Honor the response's retry guidance, reduce mint frequency, and retry after the window. Do not create duplicate links in a tight loop. |
| Per-read rate limit | Redirect reads return a rate-limit response after more than 60 requests per minute from the same IP. | Stop the read burst and let the window reset. Do not use retries to probe codes. |

The `LINK_NOT_FOUND` row is also listed in the [Error Code Reference](/reference/error-codes).

## Decision checklist

1. **Preserve the exact code.** Copy it from the returned `short_url`; do not
   normalize, decode, truncate, or substitute characters. Codes are case-sensitive.
2. **Identify the endpoint.** A browser failure on `GET /l/:code` is a redirect
   lookup or target-validation issue. `POST /public/lp/:code/convert` requires
   a published landing page and returns JSON.
3. **Verify the record in your tenant.** Use the authenticated links API or
   dashboard to confirm that the code exists and, for a conversion, that the
   page is `PUBLISHED`. These are tenant-owned records and controls; do not
   infer state from a public 404.
4. **Check expiry and publication.** Re-mint an expired short link. Publish a
   draft landing page and use the new/current published code. An archived or
   unpublished page is not a conversion target.
5. **Check the target scheme.** For a redirect, the stored target must still be
   `http://` or `https://`. A non-HTTP(S) target is refused even if the code row
   exists.
6. **Separate validation from throttling.** Fix a `422 VALIDATION_ERROR` before
   another mint. For a rate limit, wait for the documented window; only that
   transient bucket is retryable.
7. **Retry only after state changes.** Once the code is confirmed published and
   unexpired, retry the conversion once. A repeated 404 with no state change is
   the same deterministic lookup miss.

<Note>
  A browser's branded error page is intentionally self-contained: it is `noindex`,
  contains no raw-code echo, and makes no tracking request. API clients should
  continue to parse the JSON envelope rather than scrape browser HTML.
</Note>

## What not to do

* **Do not retry a 400/404 to get a different outcome.** Unknown, expired, and
  unpublished codes are deterministic lookup misses.
* **Do not probe random code prefixes or nearby codes.** A short code is an
  identifier, not a search space. Random probing adds load, can trigger the
  per-read limit, and cannot repair the original link.
* **Do not convert a draft or archived page.** Publish it first and use the
  published short code returned by the publish operation.
* **Do not keep an expired URL in campaigns, messages, QR codes, or ads.**
  Re-mint, replace the shared URL, and then verify the new code once.
* **Do not bypass the URL scheme check.** Never use a `javascript:`, `data:`,
  or other non-HTTP(S) target to make a redirect resolve.
* **Do not treat the browser HTML as an API contract.** API callers must use
  the JSON response and its `error.code`.

## Related references

* [Short links with click tracking](/guides/short-links-and-click-tracking) —
  minting, branded domains, redirect behaviour, rate limits, and click analytics.
* [Short links cookbook](/guides/short-links-cookbook) — runnable minting and
  landing-page examples.
* [Short links concept](/concepts/short-links) — code, publication lifecycle,
  and tenant ownership model.
* [Links API reference](/api-reference/links) — request and response schemas.
* [Error Code Reference](/reference/error-codes#resources) — the `LINK_NOT_FOUND`
  row and the surrounding 404 taxonomy.
* [Troubleshooting hub](/reference/troubleshooting-hub) — the runbook index.

## When to contact support

Contact support if the authenticated record is `PUBLISHED`, not expired, and
its target is a valid HTTP(S) URL, but the public redirect or conversion still
returns the same error after one state-confirming retry. Include the endpoint,
the tenant-visible link or page id, the response's `meta.request_id`, and the
approximate time of the request. Do not include secret API keys or probe results
for unrelated codes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.