Errors
The error envelope, the error codes the API returns, and how to recover from each.
The API signals failures with standard HTTP status codes and, in most cases, a consistent JSON body. Anything with a status code of 300 or higher should be treated as a failure.
Error envelope
Every error response returned by the API shares the same shape. A few errors are returned before the request reaches the API and use a different body (see Errors outside the envelope):
{
"status": 400,
"detail": "Human readable error message.",
"code": "validation_error"
}| Field | Type | Description |
|---|---|---|
status | integer | Mirrors the HTTP status code. Anything greater than 299 is a failure. |
detail | string | Human-readable message. Useful for logs, but do not branch on its exact text. |
code | string | Stable, machine-readable code. Branch on this. For 5xx errors returned by the API it is unexpected_error. |
Branch your error handling on code, not on detail, since the human-readable message may change. Only the error envelope has a code field.
Errors outside the envelope
These errors are returned before the request reaches the API. Their body is not the error envelope and has no code field:
| Status | When | Body |
|---|---|---|
403 | x-api-key is missing or invalid. See Authentication. | { "message": "..." } |
403 | The path or HTTP method doesn't exist, even with a valid x-api-key. | { "message": "..." } |
413 | The request is too large, for example a body over 10 MB. | Plain text or { "message": "..." } |
429 | You exceeded your rate limit or daily quota. See Rate limiting. | { "message": "..." } |
504 | The API didn't respond in time (about 30 seconds) or couldn't be reached. | { "message": "..." } |
Branch on the HTTP status first, and read code only when the body is the error envelope. Don't assume every error body is JSON, and don't branch on the message text, since it may change.
Request bodies between 6 MB and 10 MB do reach the API, and are rejected with 400 and code: validation_error.
Client errors (4xx)
Client errors mean the request needs to be changed before retrying; an identical retry will fail the same way. The code field takes one of these values:
code | Meaning | How to recover |
|---|---|---|
missing_fields | A required field was absent. | Add the missing field(s) named in detail. |
validation_error | The request failed validation. | Fix the fields named in detail. |
invalid_body | The request body could not be parsed. | Send valid JSON with Content-Type: application/json. |
invalid_field | A field had an unexpected name or type. | Correct the field to match the endpoint's schema. |
unsupported_value | A field held a value the API doesn't accept. | Use a supported value (check the endpoint reference). |
empty_value | A field was present but empty. | Provide a non-empty value. |
invalid_parameter | A query or path parameter was invalid. | Correct the parameter named in detail. |
invalid_credentials | Authentication failed. | Check your x-api-key and x-client-id, and send the header names in lowercase. See Authentication. |
invalid_batch_size | The batch size was outside the allowed range. | Reduce the number of items in the batch. |
max_batch_size_exceeded | The batch exceeded the maximum item count. | Split the request into smaller batches. |
http_validation_error | The request failed structural validation. | Review the request against the endpoint schema. |
unsupported_profession | The professionCode isn't recognized. | Use a code returned by GET /v2/professions. |
unsupported_state | The professionState isn't supported for this profession. | Confirm the state/profession pairing via GET /v2/professions. |
restricted_profession | Your account isn't authorized for this profession. | Contact support@propelus.com to request access. |
restricted_state | Your account isn't authorized for this state. | Contact support@propelus.com to request access. |
restricted_environment | The operation isn't allowed in this environment. | Confirm you're calling the correct environment. |
restricted_access | Your x-client-id isn't recognized, or your account isn't authorized for this resource. | Check your x-client-id and send the header names in lowercase (see Authentication), or contact support@propelus.com to request access. |
not_found | The requested resource (for example, a professional, credential, or webhook) doesn't exist. | Check the ID in the request path. |
monitoring_already_exists | The professional is already enrolled in monitoring for this product. | Use the existing monitoring instead of creating a new one. |
monitoring_not_found | The referenced monitoring doesn't exist, or the professional isn't monitored for that product. | Check the monitoring ID, or the professional ID and product, in the request. |
already_queued | Every credential in the batch is already queued for verification from a previous batch. | Wait for the original batch's results; each entry in errors includes the original batchId in its detail. |
Rate limiting (429)
A 429 Too Many Requests means you've exceeded your rate limit. Its body is { "message": "..." } rather than the standard envelope (see Errors outside the envelope). Retry with exponential backoff and jitter; see Rate limits for the full backoff strategy.
Server errors (5xx)
A 5xx indicates a problem on the Propelus side, not with your request. These are safe to retry:
- Retry with exponential backoff and jitter (see Rate limits).
- When the API returns the error, the
codefield isunexpected_error. A504returned before the request reaches the API has nocode(see Errors outside the envelope); retry it the same way. If the error persists, contact support@propelus.com with the endpoint you called and the approximate timestamp so the issue can be traced.