Guides
Errors, retries and idempotency
The shape of every error, which failures are safe to retry, and how an Idempotency-Key keeps a retried request from running twice.
Every error has the same shape, a stable error code you can branch on, and a request ID you can quote. Read this page before you write retry logic: some failures are replayed exactly, and some must be retried with a new key.
The error shape#
{
"error": "INVALID_REQUEST",
"message": "The request is not valid.",
"errors": [
{ "field": "limit", "code": "invalid_value", "message": "limit must be a whole number from 1 to 100." }
],
"request_id": "req_..."
}erroris a stable code. Branch on it, never onmessage.messageis a plain sentence for a person.errorslists every problem found in a request that was not valid, so you can fix them all in one go. It is empty for every other error. Each item has afield(a dotted path such assubscriber.member_id, ornullfor the request as a whole), a stablecode, and amessage. A message never repeats the value you sent.request_idis the ID of the request. The same ID is in thex-request-idresponse header of every reply, errors and successes. Quote it when you contact support.
The field code is one of required, invalid_type, too_short, too_long, too_small, too_big, invalid_format, invalid_value, unknown_field, invalid_body, invalid, or, for an eligibility request, one of the findings listed in Eligibility.
curl "https://sandbox.myclaimhouse.com/api/v1/payers?limit=500" -H "Authorization: Bearer $CLAIMHOUSE_KEY"Error codes#
| Code | HTTP status | What it means |
|---|---|---|
UNAUTHORIZED | 401 | A valid API key is required. Send it as "Authorization: Bearer <key>". |
PERMISSION_DENIED | 403 | This API key is not allowed to do that. |
NOT_FOUND | 404 | Not found. |
INVALID_REQUEST | 422 | The request is not valid. |
IDEMPOTENCY_KEY_REQUIRED | 400 | POST and PATCH requests need an Idempotency-Key header. |
IDEMPOTENCY_KEY_REUSED | 422 | That Idempotency-Key was already used with a different request. |
IDEMPOTENCY_KEY_IN_USE | 409 | A request with that Idempotency-Key is still running. Retry shortly. |
TOO_MANY_REQUESTS | 429 | Too many requests of this kind lately. Wait, then try again. |
REQUEST_TIMEOUT | 408 | The request body stopped arriving, so the request was stopped. Send it again. |
PAYLOAD_TOO_LARGE | 413 | The request body is larger than 1 MB. |
TIMEOUT | 504 | The request took too long to finish. It may still have taken effect: look it up before sending it again with a new Idempotency-Key. What it made is found with GET /api/v1/eligibility?request_id=<this request_id>, and the same filter on /api/v1/claims and /api/v1/attachments (a key with read permission). |
PAYER_REJECTED | 422 | The payer rejected the check. The check object says what to change, and whether resending can help. |
PAYER_UNAVAILABLE | 502 | The payer's system is not answering right now. Nothing needs to change: send the check again later. |
NETWORK_ERROR | 502 | The check could not be completed because the payer network failed. It is not billed. Send it again later. |
ELIGIBILITY_UNAVAILABLE | 503 | Eligibility checks are not available in live mode yet. Use a test key. |
CLAIMS_UNAVAILABLE | 503 | Claims are not available in live mode yet. Use a test key. |
ATTACHMENTS_UNAVAILABLE | 503 | Attachments are not available in live mode yet. Use a test key. |
ATTACHMENTS_NETWORK_ERROR | 502 | The attachment network did not finish. The attachment is still open and nothing was lost: close it again. |
CONFLICT | 409 | The resource is not in a state that allows this, or it changed while the request was handled. Read it, then decide whether to send the request again. |
INTERNAL | 500 | Something went wrong on our side. Quote the request ID if you contact us. |
An eligibility check that is rejected, unavailable or failed carries the check itself next to the error, so you can always find the check an error is about. See Eligibility.
Which failures to retry#
| What you got | What it means | What to do |
|---|---|---|
| No response (the connection dropped, or you timed out first) | You do not know whether the request ran. | Send the same request again with the same Idempotency-Key. You get the first answer, or the request runs once. |
401, 403, 404, 422 | The request, the key or the ID is wrong. | Fix it. Sending it again unchanged gets the same answer. |
409 IDEMPOTENCY_KEY_IN_USE | An identical request is still running. | Wait a moment and send the same request with the same key. |
502 PAYER_UNAVAILABLE or NETWORK_ERROR | The payer or the network failed. Nothing is billed. | Send the check again later with a new Idempotency-Key. |
500 INTERNAL | Something went wrong on our side. | Send it again with a new key. If the error carries a check, read it first: the check was made. |
504 TIMEOUT | The request took longer than 45 seconds. It may still have taken effect. | Look it up before you send it again: see below. |
A request that fails after it has started is never run a second time by a retry. That is the next section.
Idempotency#
Send an Idempotency-Key header with every POST and PATCH. A request without one is refused with 400 IDEMPOTENCY_KEY_REQUIRED.
- The key is 1 to 255 printable ASCII characters, with no spaces. A UUID is a good choice. A key that is not of that form is refused with
400 IDEMPOTENCY_KEY_REQUIRED, like a missing one. - Never put patient information in a key. Keys are stored and kept in the request log.
- The same key with the same method, path, query and body returns the stored answer, with the header
idempotent-replayed: true. The check is not made again and not billed again. A replay is the stored body, so itsrequest_idis the first request's; thex-request-idheader is the new request's. - The same key with anything different is refused with
422 IDEMPOTENCY_KEY_REUSED. - While the first request is still running, a duplicate waits up to 10 seconds, then answers
409 IDEMPOTENCY_KEY_IN_USE. - Stored answers are kept for 24 hours, then deleted. After that, the same key starts a new request.
The outcome is final once the request has started#
Once Claim House has started a request, its outcome is final, including a failure. A retry with the same key replays that stored 502, 500 or 504; it does not run the request again, because the request may already have reached a payer.
So the rule is: a retry after no response reuses the key; a retry after an error response is a new attempt and uses a new key. A request that failed before it started (for example 401 UNAUTHORIZED) can be sent again with the same key.
After a timeout#
A 504 TIMEOUT means Claim House stopped waiting, not that nothing happened. For an eligibility check, find out before you send it again. Use the request_id of the 504, or your Idempotency-Key:
curl "https://sandbox.myclaimhouse.com/api/v1/eligibility?idempotency_key=my-key-1" -H "Authorization: Bearer $CLAIMHOUSE_KEY"Each check carries the request_id and the idempotency_key of the request that made it. If a check is there, read its answer: if its state is still pending, it is still running, so read it again shortly. If no check is there, send the check again with a new key.
This needs a key with read permission. An integration that submits checks with a submit-only key should keep a separate read key for this lookup.
Request size#
A request body over 1 MB is refused with 413 PAYLOAD_TOO_LARGE, before anything is recorded. An attachment upload has its own limit (see Attachments), and one whose body stops arriving for 15 seconds is refused with 408 REQUEST_TIMEOUT.