Skip to main content
HoundDog API Documentation

Idempotency

Networks fail: a request can succeed on our side while your client times out. To retry a POST safely, send an Idempotency-Key header. A retry with the same key does not act twice.

POST /api/v2/parties
Idempotency-Key: 4f1c2e8a-7d3b-4c55-9a0e-1b2c3d4e5f60

Rules

  • Where: any v2 POST. GET, PATCH and DELETE ignore the header.
  • The key: an opaque string of 1 to 255 characters that you generate, one per logical operation (a UUID is a good choice). It is compared byte for byte: case and internal spaces count; avoid leading or trailing spaces. Keys are per API key: two of your keys never share them.
  • How long: a key is remembered for 24 hours after its request completes.
  • What is remembered: only successful (2xx) requests. A refused request (4xx, 5xx) is not remembered, so a retry is simply evaluated again.
  • Same request: the parameters you sent, plus the SHA-256 of each uploaded file. The raw body is not compared, so a retried multipart upload (with a new boundary) still matches.

What a retry gets

Situation Response
Same key, same request, first one finished The resource the first request created or acted on, rendered as it is now (not a copy of the first response), with the header Idempotency-Replayed: true. An action that is not naturally repeatable, such as resend, is not performed again
Same key, different request 422 idempotency_key_reused
Same key while the first request is still running 409 idempotency_in_progress. Wait and retry: this protects you when your client gave up before we finished
Same key, but what the first request created no longer exists 409 idempotency_not_replayable ("the resource this key created no longer exists"), for example a record a dashboard user deleted since, or a certificate that was since converted into a tax form
Same key on an endpoint whose first response held a one-time value 409 idempotency_not_replayable ("the original response contained a one-time value; create a new one"). These are POST /webhook_subscriptions, POST /webhook_subscriptions/:id/rotate_secret and POST /direct_uploads

Because a replay re-renders the resource under the current rules, it never repeats a one-time secret, and a field that needs a grant appears only if your key and account may see it at the time of the replay. A replay returns the earlier result even if a feature it needed has since been switched off; it never performs the action again.

A signing request your earlier call superseded or invalidated still exists, so its replay renders it as no_longer_needed.

Good to know

  • Replays count against your rate limit like any request (Rate limits).
  • In the rare event our idempotency store is unavailable, the request is processed without replay protection rather than refused. A retry during such an incident may be told the first request is still running (409 idempotency_in_progress), and may run again later.
  • See Errors for the error shape.