Developer docs

Get started

Errors

In short

When a request fails, you get an HTTP status and a JSON body with an error.code, such as VALIDATION_ERROR. Check the code in your program, not the message. Some errors are worth a retry; most mean you need to fix the request.

What an error looks like

Every error has the same shape. success is false, and the error object holds the details.

Error body
{
  "status": 409,
  "success": false,
  "error": {
    "code": "CONFLICT",
    "message": "Short code \"summer-sale\" is already taken on domain \"clik.is\""
  }
}
  • status — the HTTP status, repeated in the body.
  • error.code — a fixed name for the problem. Your code can rely on it.
  • error.message — a sentence for people. Its words may change, so do not match on it.
  • error.details — extra facts. Only some errors send it, and its shape depends on the code.

Every error code

401UNAUTHORIZEDThe key is missing, malformed or unknown, or the account that made it no longer exists.Send Authorization: Bearer clik_live_… with a key from Settings → API.
401API_KEY_REVOKEDSomeone revoked this key in Settings → API.Create a new key and replace the old one.
401API_KEY_EXPIREDThe key is past its expiry date.Create a new key.
402UPGRADE_REQUIREDThe request uses a feature your plan does not include, or adds a folder or tag past your plan’s count. error.details names the feature, the field and the required_plan.Leave the field out, or upgrade the workspace.
402WORKSPACE_PAYMENT_REQUIREDThe workspace is waiting for its first payment. Until then only reading the workspace (bootstrap and usage) works.Finish the payment in the Clikso dashboard. Do not retry until it has gone through.
402WORKSPACE_PAUSEDThe workspace is read-only (paused): it is not the account’s default and has no active paid plan. Reads and the analytics reads still work; changes do not. Its short links keep redirecting.Add a paid plan for the workspace in the Clikso dashboard, or make it your default workspace there. Reads need no change.
403FORBIDDENThe key’s permission or role is too low for this action, the Workspace-Id header names a different workspace, or the key’s creator is no longer a member.Check the key’s permission and your role. If you send Workspace-Id, it must match the key’s workspace.
403API_KEY_NOT_ALLOWEDThis endpoint does not accept API keys at all (for example billing, members, API keys or revealing a link password).Use only the endpoints in the API reference.
403ACCOUNT_BANNEDThe account that created the key is suspended.Contact support. A new key will not help.
403EMAIL_NOT_VERIFIEDThe account that created the key has not verified its email address.Sign in to the dashboard and verify the email.
404NOT_FOUNDThe link, folder, tag or domain does not exist in this key’s workspace (or was deleted).Check the id. Ids from another workspace are never found.
409CONFLICTThe short code is already taken on that domain. Also returned when you try to delete a link that was banned for abuse.Pick another short_code, or leave it out to get a random one.
422VALIDATION_ERRORA field is missing or invalid. error.message says which; error.details.field may name it, or error.details may map field names to messages.Fix the field and send the request again.
422DESTINATION_BLOCKEDThe destination URL is not allowed: another link shortener, or a domain on Clikso’s blocklist.Show error.message to the user as it is. Do not retry.
429RATE_LIMITEDToo many requests in one minute — for this key, or for this workspace’s analytics or AI slug quota.Wait the number of seconds in the Retry-After header, then try again.
429USAGE_LIMIT_REACHEDA plan quota is used up: links this month, AI slugs today, or analytics requests today.Wait for the reset (analytics sends details.resets_at) or upgrade.
500INTERNAL_ERRORSomething failed on Clikso’s side.Retry with a growing delay. If it keeps failing, contact support.

Errors with details

VALIDATION_ERROR

error.message names the first problem. Is a value too long, or not a date? Then details.field holds the field's name, such as title or expires_at. For some fields, error.details maps each field name to its message instead. Tracking ids are one example:

422 VALIDATION_ERROR
{
  "status": 422,
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "GA4 Measurement ID has an invalid format",
    "details": {
      "ga4_measurement_id": "GA4 Measurement ID has an invalid format"
    }
  }
}

Show each message next to the field it names. If there are no details, show error.message.

DESTINATION_BLOCKED

The destination URL is another link shortener, or a site on Clikso's blocklist. Every URL in the request is checked, including A/B, country and device URLs. Show error.message to the person as it is: it explains which URL was refused. Do not retry the same URL.

422 DESTINATION_BLOCKED
{
  "status": 422,
  "success": false,
  "error": {
    "code": "DESTINATION_BLOCKED",
    "message": "This destination URL isn't allowed: \"bit.ly\" is a link shortener, and Clikso links can't point at another short link. Use the final destination URL instead.",
    "details": {
      "destination_url": "This destination URL isn't allowed: \"bit.ly\" is a link shortener, and Clikso links can't point at another short link. Use the final destination URL instead."
    }
  }
}

UPGRADE_REQUIRED

You set a field your plan does not include, such as country rules on Free. error.details says which feature, which field, the lowest plan that has it, and your current plan.

402 UPGRADE_REQUIRED
{
  "status": 402,
  "success": false,
  "error": {
    "code": "UPGRADE_REQUIRED",
    "message": "Geo targeting needs the Pro plan or higher.",
    "details": {
      "feature": "geoTargeting",
      "field": "geo_targeting",
      "required_plan": "pro",
      "current_plan": "free"
    }
  }
}

On an update, you can always send a value the link already has, or clear a field. Only a new or changed value is checked.

Adding a folder or tag past your plan's count also returns 402. Then details.feature is folders or tags, details.field is null, and details.limit and details.current give the count.

WORKSPACE_PAYMENT_REQUIRED and WORKSPACE_PAUSED

Every account has one default workspace that's free forever. Each extra workspace needs its own paid plan, and it waits for its first payment before it can be used. An extra workspace is paused (read-only) when its paid plan ends, or when it stops being the default without a paid plan. Both answer with 402 and say which state the workspace is in:

402 WORKSPACE_PAUSED
{
  "status": 402,
  "success": false,
  "error": {
    "code": "WORKSPACE_PAUSED",
    "message": "This workspace is read-only. Your short links still work. Add a paid plan or make it your default to make changes.",
    "details": {
      "access_state": "paused",
      "workspace_id": "8a1f2c3d-4b5e-4f60-9a7b-1c2d3e4f5a6b"
    }
  }
}
  • WORKSPACE_PAYMENT_REQUIRED — the workspace is waiting for its first payment. Only reading the workspace works (Get workspace details and Get usage). Finish the payment in the dashboard.
  • WORKSPACE_PAUSED — the workspace is read-only. It is not the account's default and has no active paid plan. Reads and the click analytics still work, and the short links keep redirecting. Changes need a paid plan, or the owner can make it their default workspace in the dashboard.

workspaces[].access_state in Get workspace details tells you the state before you hit either error: null for a normal workspace. workspaces[].is_default is true when the workspace is its owner's default, which is never paused. It is the owner's flag: a member's API key sees the same value.

USAGE_LIMIT_REACHED

A plan allowance is used up. For the analytics API, error.details.resets_at says when the daily count starts again, at midnight UTC.

429 USAGE_LIMIT_REACHED
{
  "status": 429,
  "success": false,
  "error": {
    "code": "USAGE_LIMIT_REACHED",
    "message": "This workspace has used its 100 analytics API requests for today. The quota resets at 00:00 UTC.",
    "details": {
      "resets_at": "2026-10-10T00:00:00.000Z",
      "limit": 100
    }
  }
}

The monthly link allowance and the daily AI slug allowance send the same code, without details. The Limits page lists every allowance.

When to retry

  • 429 RATE_LIMITED — wait the number of seconds in the Retry-After header, then send the same request again.
  • 429 USAGE_LIMIT_REACHED — do not retry right away. Wait until the allowance resets, or upgrade.
  • 500 INTERNAL_ERROR — retry after a short wait. Double the wait each time, and stop after a few tries.
  • Network errors — retry like a 500. For a create, list your links first, so you do not make the same link twice.
  • Any other 4xx — do not retry. The same request will fail the same way. Fix it first.

Good to know

  • 403 API_KEY_NOT_ALLOWED is a bug in your code, not a key problem. Check that the endpoint is in the API reference.
  • A 404 for an id from another workspace is on purpose. The API never says whether that id exists elsewhere.
  • Each API reference page lists the errors that endpoint can send.