Errors
The envelope, and what to branch on.
Every error is the same shape.
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "duration_minutes must be between 5 and 120",
"param": "duration_minutes",
"request_id": "req_8f2c...",
"doc_url": "https://docs.experthire.io/..."
}
}
Branch on code, never on message. Messages are written for people and change;
codes are a closed set.
Quote request_id when you contact us. It is on every response, including successes.
The ones you will actually hit
| Code | Status | What to do |
|---|---|---|
invalid_api_key | 401 | Check the prefix. An ehp_ key is the wrong product |
secret_key_required | 401 | You sent a session token to a server-only endpoint |
validation_failed | 400 | Read param |
insufficient_credits | 402 | Stop and tell the customer |
sandbox_quota_exceeded | 402 | The month's test allowance is used up |
assessment_not_found | 404 | Wrong id, wrong organisation, or wrong environment |
report_not_ready | 404 | Not completed yet. On test it never will be |
rate_limited | 429 | Back off for Retry-After |
idempotency_key_reuse | 409 | Same key, different body |
Not-found means several things
An id from another organisation, or from the other environment, returns
assessment_not_found rather than a permission error. That is deliberate: a distinct
error would let an id be probed for existence across tenants.
Retrying safely
Send Idempotency-Key on every create. A retry then replays the original response
instead of creating a second assessment and billing twice.
A failed request releases its key, so a retry after a 500 does the work rather than replaying the failure.
Next
- Reference — rate limits, pagination, idempotency