ClientSphereDocs
Guides

Errors

The error response shape the ClientSphere API returns, and what each error code means.

Every failure returns a JSON body with the same shape, whatever went wrong:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Resource not found."
  }
}

Branch on error.code. It is stable and meant to be read by your code. message is meant for a human reading a log and may be reworded.

Codes

Statuserror.codeMeaning
400VALIDATION_ERRORThe body failed validation. Carries a details array naming the fields.
400INVALID_IDA path parameter is not a well-formed UUID. Note this is not a 404.
400INVALID_EMAILAn email-shaped path parameter or field is not a valid address.
400INVALID_CONTACT_IDA contactId in the body is not a well-formed UUID.
401UNAUTHORIZEDNo API key was supplied at all.
401INVALID_KEYThe key is unknown, deactivated, or its prefix does not match its mode.
401KEY_EXPIREDThe key was valid but has passed its expiry date.
403FORBIDDENThe key is valid but lacks the permission this endpoint needs.
404NOT_FOUNDNo such record in this workspace.
409NO_ELIGIBLE_ACTORCreating a widget found nobody to attribute it to — see below.
429RATE_LIMITEDToo many requests — see Rate limits.
500INTERNAL_ERRORSomething failed inside the API.

Sending transactional email adds a few statuses of its own — 202, 409, 413, 422 and 502 — which are documented on that endpoint rather than here.

NO_ELIGIBLE_ACTOR

Widgets record who created them, and that column cannot be null. An API key is not a person, so the API attributes the widget to a real user: the one who created the key, failing that the workspace owner, failing that any active user.

If none of those exist — typically because the person who created the key has since left and no other active user remains — the request is refused with 409 rather than writing a row it cannot attribute. Reactivate a user in the workspace and retry; the request is unchanged and safe to send again.

A bad id is a 400, not a 404

This is the one that surprises people. An id that is not a well-formed UUID is rejected before anything is looked up, so it comes back 400 INVALID_ID:

{
  "error": {
    "code": "INVALID_ID",
    "message": "Invalid account ID format."
  }
}

404 NOT_FOUND means the id was well-formed and simply matched nothing. So if you are threading ids through from somewhere else, a 400 points at the plumbing — a truncated value, a slug where a UUID belongs — and a 404 points at the record.

401 and 403 are different problems

They are easy to conflate and they need opposite fixes.

401 is about the key itself: absent (UNAUTHORIZED), unknown or deactivated or carrying the wrong prefix for its mode (INVALID_KEY), or past its expiry (KEY_EXPIRED). 403 means the key authenticated perfectly well and is simply not allowed to do this — the fix is the key's permissions, in Settings → API Keys, not the credential.

The 403 message names the permission that was missing, so you rarely have to guess which one to grant.

Validation errors

A 400 VALIDATION_ERROR includes a details array identifying what failed, so you can surface it rather than showing a generic message. Each entry names the field in path and explains the problem in message:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input.",
    "details": [
      {
        "code": "invalid_type",
        "expected": "string",
        "received": "undefined",
        "path": ["name"],
        "message": "Required"
      },
      {
        "code": "invalid_string",
        "validation": "email",
        "path": ["email"],
        "message": "Invalid email"
      }
    ]
  }
}

path is an array because it addresses nested fields — a problem inside an array element arrives as ["items", 0, "quantity"]. Joining it with . is usually enough to point a user at the right input.

500s

INTERNAL_ERROR means the failure was ours, not your request's. A read is always safe to retry. For a write, the request may or may not have taken effect, so re-check the record's state before sending it again rather than assuming it was lost.

404 is workspace-scoped

Every request is scoped to the workspace its key belongs to. A 404 means no such record in that workspace — an id that is perfectly real in another workspace, or on the other side of the test/live divide, still returns 404. When a record you know exists returns 404, check you are not reading with a sk_test_ key something written with a sk_live_ one.

On this page