Errors
The API uses conventional HTTP status codes and returns every error as the same small JSON envelope. The status code tells you whether retrying can help; the errorCode tells you exactly what went wrong.
The error envelope
{
"message": "You can only have up to '100' pending bulk requests at any given.",
"errorCode": "integration/too-many-pending-requests"
}
| Field | Description |
|---|---|
errorCode | A stable machine-readable identifier, always prefixed integration/. Branch on this. |
message | Human-readable summary, for logging and support. Its wording can change without notice — never parse it or compare against it. |
Status codes
| Code | Meaning |
|---|---|
400 | The request was malformed or failed validation. Fix the payload; retrying unchanged will not help. |
401 | Authentication failed, or your key's profile may not access something you referenced. See the note below. |
403 | Your key's profile may not access a specific group, framework or custom property. |
404 | The thing you asked for does not exist, or is a queued request whose result has been archived. |
409 | The request conflicts with the current state. |
429 | You have too many bulk requests in flight. See Rate limits. |
500 | Something failed on our side. The error is logged and investigated; contact support with the correlation id if it persists. |
Most APIs return 403 when you are authenticated but not permitted. This one returns 401 in some of those cases — with errorCode integration/authorization and the message "Forbidden" — while other permission failures do return 403, with a more specific code such as integration/group-access-forbidden.
So do not infer "my key is invalid" from a bare 401. Read the errorCode: integration/authentication means the key itself was rejected, integration/authorization means the key is fine but the profile may not do what you asked.
Error codes
These are the codes the published endpoints return.
errorCode | Status | What it means |
|---|---|---|
integration/authentication | 401 | The API key is missing, malformed, or revoked. |
integration/authorization | 401 | The key is valid but its profile may not perform this action. |
integration/input-invalid | 400 | A value in the payload is not acceptable — wrong type, unparseable date, unknown unit of measure. |
integration/input-missing | 400 | A required field was absent. |
integration/data-point-input-type-not-supported | 400 | The data point you addressed does not accept the kind of value you sent. |
integration/custom-property-not-identifier | 400 | The custom property you referenced exists but is not an identifier, so it cannot be used to match companies. |
integration/custom-property-access-forbidden | 403 | Your profile does not own the custom property you referenced. |
integration/framework-access-forbidden | 403 | The framework is not accessible to your profile. |
integration/group-access-forbidden | 403 | The group is not accessible to your profile. |
integration/company-mapping-request-not-found | 404 | No mapping request exists for that correlation id. |
integration/archived-request | 404 | The request completed long enough ago that its result is no longer retrievable. |
integration/too-many-pending-requests | 429 | You already have 100 bulk requests in flight. |
integration/unknown-error | 500 | Unhandled failure on our side. |
Codes are stable. New ones may be added, so treat an unrecognised code as a generic failure of its status class rather than crashing.
HTTP errors are not the same as item failures
An error envelope means the request failed. It does not cover the far more common case of a request that succeeded while individual rows inside it did not.
A bulk request that returns 200 and later reaches a terminal state may still contain companies that matched nothing, rows your profile could not write to, or values that failed validation. Those outcomes are reported per item in the result you fetch after polling — not as HTTP errors.
If your integration only checks status codes, it will report success on runs where nothing was actually written. Read the per-item results. Asynchronous processing covers the polling loop that gets you there.