Error reference

Every error is JSON with an `error` field. This page lists them all, by status, taken from the server's source code.

On this page 5
  1. The shape of an error
  2. What each status means
  3. Machine-readable codes
  4. Every error, by status
  5. Related

The shape of an error

Every error under /v1 is JSON, never an HTML page:

JSON
{ "error": "slug already exists in this workspace" }

Some errors add fields: message (a sentence you can show to a person), reason (which limit or check), limit, resetsAt, hint or upgradeUrl. When error is a single snake_case word it's a stable code you can branch on; the table below lists every one. Any other error is a plain-English sentence: show it or log it, but don't match on its exact wording, because it can change.

What each status means

Status Meaning What to do
400 The request is wrong: a missing or invalid field, or a body that isn't valid JSON Fix the request. The message names the field
401 No key, a wrong key, or the wrong kind of key Send the secret key as Authorization: Bearer st_live_… (server), or the publishable key in the body (apps). See Keys
402 Your plan doesn't include this, or a plan limit is reached Existing links keep working. Upgrade, or wait for the next month for the tap limit
403 Signed in, but not allowed (a viewer, or two-factor sign-in needed) Ask an owner or admin, or sign in again with your code
404 No such link, webhook, delivery or domain in this workspace, or an unknown /v1 path Check the id or slug. Another workspace's ids are always 404
409 It already exists, or it's busy right now Use another slug or name, or try again in a moment
410 The link is gone Create a new link
413 The body is too large Send fewer items per call (a batch takes up to 500 links)
421 The request reached the server directly instead of through your link domain Use https://strait.link or your link domain
422 The domain you asked the App Links checker about can't be found in DNS, or an Idempotency-Key was reused with a different body Check the spelling, or use a new key
429 Too many requests Wait for Retry-After seconds when it's sent. See Rate limits
500 Our fault: { "error": "internal error" }, with no internal details Retry later. If it keeps happening, write to support@straitlink.in
502 Our certificate provider didn't answer (custom domains) Try again in a minute; the message says whether anything was saved
503 The feature isn't switched on, or is read-only right now Try again later

Machine-readable codes

error Status When What to do
destination_blocked 400 A link's destination failed the unsafe-destination check. reason says why (invalid_url, scheme, credentials_in_url, ip_address, blocked_domain, …) Use a public https address
invalid_domain 400 The App Links checker got something that isn't a domain Send a domain such as example.com
refused 400 The App Links checker was asked about a private address, an IP address or a non-public name Check a public domain
invalid_report 400 A link report (POST /v1/report) is missing a field or has a bad one; message says which Fix the field
invalid_url 400 The link checker (POST /v1/tools/link-check) got something that isn't a full link Send a full link such as https://yourapp.page.link/abc
dns_failed 422 The App Links checker couldn't find the domain in DNS Check the spelling
unauthorized 401 A link endpoint was called with no Authorization header (also an operator-only endpoint without its key) Send Authorization: Bearer st_live_…
plan_required 402 Custom domains on a plan without them Upgrade to Scale. See Custom domains
mfa_required 403 A dashboard session that still needs its two-factor code Sign in again and enter your code
fresh_mfa_required 403 Closing a workspace needs a two-factor code from the last 10 minutes Enter a current code, then try again
key_scope 403 A secret key used outside its access (a read-only key writing, a links-only key outside /v1/links) Use a key with the access the call needs (Keys)
invalid_idempotency_key 400 The Idempotency-Key header isn't 1 to 255 letters, digits or . _ : - Fix the key. See Retry safely
idempotency_key_in_use 409 A request with the same Idempotency-Key is still running; sends Retry-After: 1 Retry after a second
idempotency_key_reused 422 The Idempotency-Key was used in the last 24 hours with a different body Use a new key for a new request
link_blocked 409 Turning a link back on (PATCH /v1/links/{slug} with {"isActive": true}) when it was disabled for breaking the acceptable use policy It can't be turned back on; create a new link
slug_in_use 409 Turning a link back on when another active link now uses its slug or the same Firebase link Pause or rename the other link first, then try again
new_account_limit 429 A new workspace reached its first-day cap on links or taps. Adds reason (links or redirects), message, limit and resetsAt, and sends Retry-After Wait until resetsAt; the cap lifts by itself
busy 429 The link checker is at its shared limit for all visitors; sends Retry-After Wait for Retry-After (about 30 seconds)
rate_limited 429 The App Links checker, the link checker, the link report form or the health check was called too often Wait for Retry-After
domains_not_enabled 503 Custom domains aren't switched on yet Try again once they are
domains_read_only 503 Domains can't be added or removed right now Try again later

Plan limits answer 402 with the database's sentence in error, a reason and an upgradeUrl:

reason When
links The plan's new links for this month are used up
clicks This month's taps are over twice the plan's limit
webhooks The plan's number of webhooks is reached

Your existing links keep redirecting whatever the plan limit; only new links and webhooks wait. Plans and their limits are on Pricing.

Every error, by status

The list below is generated from the server's source, so it's exactly what the API can send. … stands for a value filled in at the time (a number, a name or a list). Field checks that build their message from what you sent (a slug, a hostname, a date) aren't listed one by one; they're all 400. Errors that only the dashboard can get (billing, the Firebase import) are left out.

400 Bad request

  • country must be a 2-letter country code (ISO 3166-1, e.g. IN)
  • destination_blocked
  • deviceId required: the SDK debug device id (8–64 letters, digits, - or _)
  • expiresAt must be epoch milliseconds, an ISO 8601 date-time, or null
  • from / to must be ISO dates (e.g. 2026-01-31) or epoch ms
  • invalid cursor
  • invalid_domain
  • invalid_idempotency_key
  • invalid_report
  • invalid_url
  • isActive must be true or false
  • limit must be 1 to 100
  • limit must be an integer from 1 to 100
  • linkId + device fields required
  • linkId required
  • links must be an array of 1 to … links
  • longUrl must be https
  • malformed JSON body
  • part must be one of …
  • platform + device fields required
  • platform must be 'android' or 'ios'
  • refused
  • send isActive on its own, then other fields in a second request
  • slug ([a-zA-Z0-9_-], ≤64) and https longUrl are required
  • status must be active or paused
  • tenantId is required with the admin key
  • tenantId required
  • token must be a Strait handoff token (22 base64url characters)
  • token was issued for another part
  • type the workspace link handle exactly to confirm
  • ua required: a preset (…) or a raw user agent
  • unknown linkId
  • url must be a full short link, e.g. https://…/your-slug
  • url must be a full short link, e.g. https://you.strait.link/summer

401 Unauthorized

  • analytics needs a secret key (Authorization: Bearer st_live_…); publishable keys only work for the SDK endpoints
  • download link expired or already used — start the download again
  • invalid API key
  • invalid publishable key
  • invalid secret key
  • publishable key required (find it in Dashboard → Get started)
  • secret key (Authorization: Bearer st_live_…) or publishableKey required
  • secret key or dashboard session required (Authorization: Bearer …)
  • secret key required (Authorization: Bearer st_live_…)
  • session expired — sign in again
  • sign in to the dashboard to close a workspace (a key cannot)
  • the referral report needs a secret key (Authorization: Bearer st_live_…)
  • unauthorized

402 Payment required

  • plan_required
  • (plan limit, reason: "clicks", message from the database)
  • (plan limit, reason: "links", message from the database)
  • (plan limit, reason: "webhooks", message from the database)

403 Forbidden

  • fresh_mfa_required
  • key_scope
  • mfa_required
  • not a member of this workspace
  • only an owner can close this workspace
  • only owners and admins can export (an export contains all workspace data)
  • viewers cannot add domains
  • viewers cannot create links
  • viewers cannot redeliver webhooks
  • viewers cannot remove domains
  • viewers cannot see webhook deliveries

404 Not found

  • delivery not found
  • domain not found
  • link not found
  • no active link "…" in this workspace
  • no such link in this workspace
  • not a trace token
  • not configured
  • not found
  • webhook not found
  • workspace not found

409 Conflict

  • A workspace can have up to … custom domains. Remove one first.
  • already delivered
  • cancel your paid plan in Plan & usage first, then close the workspace
  • idempotency_key_in_use
  • link_blocked
  • slug already exists in this workspace
  • slug_in_use
  • this delivery is being sent right now — try again in … minutes
  • This domain is already added to a Strait workspace.
  • this old link (legacyHost + legacyCode) is already imported in this workspace
  • your payment is still being confirmed — open Plan & usage in a minute, cancel the plan there, then close the workspace

413 Payload too large

  • request body too large

421 Misdirected request

  • Use https://strait.link (or your link domain); this origin only answers Strait's edge.

422 Unprocessable

  • dns_failed
  • idempotency_key_reused

429 Too many requests

  • busy
  • new_account_limit
  • QR rendering is busy: try again in a few seconds, or ask for format=svg
  • rate limited
  • rate limited: at most 30 analytics calls a minute per workspace
  • rate limited: at most 30 referral report calls a minute per workspace
  • rate limited: at most 30 usage calls a minute per workspace
  • rate limited: at most 60 QR codes a minute per workspace
  • rate limited: domain status is checked at most every few seconds
  • rate_limited
  • Too many domain changes. Try again in a few minutes.

500 Internal error

  • internal error

502 Bad gateway

  • Couldn't remove the domain from our certificate provider. It's still listed; try again in a minute.
  • Couldn't set up the domain with our certificate provider. Nothing was saved; try again in a minute.

503 Unavailable

  • domains_not_enabled
  • domains_read_only
  • REST API: every endpoint, with the statuses it answers.
  • Rate limits: what answers 429, and when to try again.
  • Webhooks: failed deliveries show HTTP <status>, timeout, unsafe_target or webhook_removed.