Handle API errors and status codes
Read the error body, what 400, 401, 403, 404, 500 and 503 mean, and why an item your key can't see answers 404.
In this article5 sections
This page covers how both APIs report a refused call, for a manage key and a hub key alike.
The error body
Every refused call answers a status code and a JSON body:
{
"error": {
"code": 400,
"message": "CaseReferenceIdExistsException",
"error_type": "ClientException",
"reason": {"case_id": "cc-1a2b3c4d5e6f70", "host_id": "ca-7e6d5c4b3a2f10"}
}
}
| Field | What it holds |
|---|---|
code | The status code again |
message | The error's name, such as CaseReferenceIdExistsException. Make your code act on this; it doesn't change with the reader's language. |
error_type | The kind of error: ClientException for a refusal, ApiException for an invalid request, SessionException for a missing key, ModelException for a refused key or a refusal from the data store, TransientException for a moment's trouble worth retrying, InternalError for a fault in CaseActive |
reason | More detail, when there is any: the clashing record's IDs, or the first field's problem. Often empty. |
errors | For an invalid request, one entry per field |
Field errors
A request with a missing or invalid field answers 400 SchemaFieldsException, with an errors entry for each field. location names the field, with dots for one inside another, and message names the problem:
{
"error": {
"code": 400,
"message": "SchemaFieldsException",
"error_type": "ApiException",
"reason": "FieldRequiredException",
"errors": [
{"domain": "json", "location": "ref_id", "locationId": "ref_id", "locationType": "schema", "message": "FieldRequiredException", "reason": "FieldRequiredException"}
]
}
}
domain is json for the body and query for the address's parameters. Common field errors:
message | What's wrong |
|---|---|
FieldRequiredException | It's missing, or empty where it can't be |
FieldValidatorFailedException | Its value isn't one allowed, such as a role, case type or stage your hub doesn't have |
FieldMinLengthException, FieldMaxLengthException | It's too short or too long |
FieldLimitTooLargeException | A list's limit is over 1000, the most a page holds |
FieldEmailTypeException, FieldPhoneTypeException | Not an email address, or not a phone number with its country code |
FieldNameTypeException | A name with characters a name can't hold |
FieldPathSlugTypeException | A Tag ID or Reference ID with characters other than letters, numbers, dashes and slashes |
FieldDateTypeException | Not a date, such as 2026-03-15 |
Fields the API doesn't know are ignored, not refused, so check your spelling against the reference.
Status codes
| Status | What it means | What to do |
|---|---|---|
| 400 | The request is invalid, or the change isn't allowed: a field error, or a refusal named in message, such as CaseReferenceIdExistsException | Correct it before sending it again |
| 401 | The key itself was refused; see Authenticate API requests with a key | Stop, and check the key |
| 403 | The key may not do this: a call a manage key can't make (BotNotAllowedException), a locked hub (ManageBillingInactiveException for a manage key, BillingReadOnlyException for a hub key once the portal is read-only), a closed case (CaseClosedException), or a change that clashed with another made at the same moment (ItemUpdateFailedException and others) | Fix the cause. For a clash, read the item again, then retry. |
| 404 | The item doesn't exist, belongs to another hub, is being deleted, or your key can't see it | Check the ID |
| 500 | InternalError: a fault in CaseActive, whose developers are told | Retry later, and contact support if it lasts |
| 503 | TransientException: the hub was too busy for a moment | Retry after a short wait, waiting longer each time |
A call that takes more than 30 seconds is cut off with a 504 from the network in front of the API, without a JSON body. Imports avoid this by running in the background.
Why an item you know exists answers 404
A hub key acts as your hub's Virtual AssistantVirtual Assistant An automated team member that posts welcome messages, check-ins and stage updates for the firm; its posts carry a Virtual Assistant badge., and sees only what the Virtual Assistant's role may see. An item hidden from that role answers 404, the same as one that doesn't exist, so the API doesn't reveal it. Today editing or deleting a published invoice, or editing a published e-sign, that the role can't see still answers 403 PublishAlreadyPublishedException. Lists leave such items out without saying so. To see what that role allows, read role::bots with a manage key; see Read roles with a manage key.
Safe to retry
- 503, and any
TransientException, after a short wait. - 400
TransactionCanceledException, which a busy moment causes, andCaseUserLimitOrTransactionExceptiononce you've checked the case isn't full. - 500, a little later.
Don't retry other 400s, a 401, a 403 or a 404 unchanged: they'll be refused again.