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
The shape of an error
Every error under /v1 is JSON, never an HTML page:
{ "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_blockeddeviceId required: the SDK debug device id (8–64 letters, digits, - or _)expiresAt must be epoch milliseconds, an ISO 8601 date-time, or nullfrom / to must be ISO dates (e.g. 2026-01-31) or epoch msinvalid cursorinvalid_domaininvalid_idempotency_keyinvalid_reportinvalid_urlisActive must be true or falselimit must be 1 to 100limit must be an integer from 1 to 100linkId + device fields requiredlinkId requiredlinks must be an array of 1 to … linkslongUrl must be httpsmalformed JSON bodypart must be one of …platform + device fields requiredplatform must be 'android' or 'ios'refusedsend isActive on its own, then other fields in a second requestslug ([a-zA-Z0-9_-], ≤64) and https longUrl are requiredstatus must be active or pausedtenantId is required with the admin keytenantId requiredtoken must be a Strait handoff token (22 base64url characters)token was issued for another parttype the workspace link handle exactly to confirmua required: a preset (…) or a raw user agentunknown linkIdurl must be a full short link, e.g. https://…/your-slugurl 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 endpointsdownload link expired or already used — start the download againinvalid API keyinvalid publishable keyinvalid secret keypublishable key required (find it in Dashboard → Get started)secret key (Authorization: Bearer st_live_…) or publishableKey requiredsecret key or dashboard session required (Authorization: Bearer …)secret key required (Authorization: Bearer st_live_…)session expired — sign in againsign 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_requiredkey_scopemfa_requirednot a member of this workspaceonly an owner can close this workspaceonly owners and admins can export (an export contains all workspace data)viewers cannot add domainsviewers cannot create linksviewers cannot redeliver webhooksviewers cannot remove domainsviewers cannot see webhook deliveries
404 Not found
delivery not founddomain not foundlink not foundno active link "…" in this workspaceno such link in this workspacenot a trace tokennot configurednot foundwebhook not foundworkspace not found
409 Conflict
A workspace can have up to … custom domains. Remove one first.already deliveredcancel your paid plan in Plan & usage first, then close the workspaceidempotency_key_in_uselink_blockedslug already exists in this workspaceslug_in_usethis delivery is being sent right now — try again in … minutesThis domain is already added to a Strait workspace.this old link (legacyHost + legacyCode) is already imported in this workspaceyour 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_failedidempotency_key_reused
429 Too many requests
busynew_account_limitQR rendering is busy: try again in a few seconds, or ask for format=svgrate limitedrate limited: at most 30 analytics calls a minute per workspacerate limited: at most 30 referral report calls a minute per workspacerate limited: at most 30 usage calls a minute per workspacerate limited: at most 60 QR codes a minute per workspacerate limited: domain status is checked at most every few secondsrate_limitedToo 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_enableddomains_read_only
Related
- 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_targetorwebhook_removed.