Errors carry a machine-readable code and a message written for a person, because the message often ends up in front of one.
The shape
{
"error": "validation_failed",
"message": "Please check the highlighted fields",
"code": "validation_failed",
"details": { "email": "Enter a valid email address" }
}
Statuses you should handle
400— the request is malformed, or a destructive call is missing?confirm=true.401— no key, a wrong key, a revoked key, or an expired one.403— the key is valid but lacks that permission, or the module is switched off.404— no such record, or no such record within this business. The two are deliberately not distinguished.409— a conflict: a duplicate where duplicates are refused, or a document whose status forbids the change.422— the body failed validation.detailsnames the field.429— too many requests. Wait and retry.
Rate limits
Requests are limited per account, and sign-in more tightly than the rest. A limited response returns 429 and says how long to wait. Bulk endpoints exist precisely so you do not have to loop: use them rather than making a request per record.
Retrying safely
GETandDELETEare safe to retry.- A
POSTthat timed out may have succeeded — look for the record before sending it again. - Back off rather than retrying immediately, and stop after a few attempts.
A 404 does not mean “deleted”. A record belonging to another business returns 404 rather than 403, because telling you it exists would leak that it exists.
Something missing or wrong here? Tell us — a question that needed asking usually means a page that needed writing.