Skip to the page
Chapters

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#

JSON
{
  "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_..."
}
  • error is a stable code. Branch on it, never on message.
  • message is a plain sentence for a person.
  • errors lists 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 a field (a dotted path such as subscriber.member_id, or null for the request as a whole), a stable code, and a message. A message never repeats the value you sent.
  • request_id is the ID of the request. The same ID is in the x-request-id response 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.

Shell
curl "https://sandbox.myclaimhouse.com/api/v1/payers?limit=500" -H "Authorization: Bearer $CLAIMHOUSE_KEY"

Error codes#

CodeHTTP statusWhat it means
UNAUTHORIZED401A valid API key is required. Send it as "Authorization: Bearer <key>".
PERMISSION_DENIED403This API key is not allowed to do that.
NOT_FOUND404Not found.
INVALID_REQUEST422The request is not valid.
IDEMPOTENCY_KEY_REQUIRED400POST and PATCH requests need an Idempotency-Key header.
IDEMPOTENCY_KEY_REUSED422That Idempotency-Key was already used with a different request.
IDEMPOTENCY_KEY_IN_USE409A request with that Idempotency-Key is still running. Retry shortly.
TOO_MANY_REQUESTS429Too many requests of this kind lately. Wait, then try again.
REQUEST_TIMEOUT408The request body stopped arriving, so the request was stopped. Send it again.
PAYLOAD_TOO_LARGE413The request body is larger than 1 MB.
TIMEOUT504The 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_REJECTED422The payer rejected the check. The check object says what to change, and whether resending can help.
PAYER_UNAVAILABLE502The payer's system is not answering right now. Nothing needs to change: send the check again later.
NETWORK_ERROR502The check could not be completed because the payer network failed. It is not billed. Send it again later.
ELIGIBILITY_UNAVAILABLE503Eligibility checks are not available in live mode yet. Use a test key.
CLAIMS_UNAVAILABLE503Claims are not available in live mode yet. Use a test key.
ATTACHMENTS_UNAVAILABLE503Attachments are not available in live mode yet. Use a test key.
ATTACHMENTS_NETWORK_ERROR502The attachment network did not finish. The attachment is still open and nothing was lost: close it again.
CONFLICT409The 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.
INTERNAL500Something 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 gotWhat it meansWhat 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, 422The request, the key or the ID is wrong.Fix it. Sending it again unchanged gets the same answer.
409 IDEMPOTENCY_KEY_IN_USEAn identical request is still running.Wait a moment and send the same request with the same key.
502 PAYER_UNAVAILABLE or NETWORK_ERRORThe payer or the network failed. Nothing is billed.Send the check again later with a new Idempotency-Key.
500 INTERNALSomething 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 TIMEOUTThe 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 its request_id is the first request's; the x-request-id header 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:

Shell
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.