Skip to content

Idempotency

Trile moves money, so every mutating request must be safely retryable. That’s enforced, not optional: a POST, PATCH, or DELETE to /v1/* requires an Idempotency-Key header.

Idempotency-Key: 7f9c2a1e-3b4d-4e6a-9c1f-2a8b0c5d6e7f
  • Client-generated, unique per logical operation. A UUID (v4 or v7) is the standard choice.
  • Up to 255 characters.
  • Scoped per business and stored for 24 hours.

Omit it on a write and you get 400 idempotency_required.

The first time Trile sees a key, it executes the request and stores the response (status + body). If the same key arrives again within 24 hours:

  • Trile returns the stored response without re-executing — even if the original was a 5xx.
  • This makes network retries, timeouts, and “did that go through?” double-submits safe.
POST /v1/subscriptions Idempotency-Key: abc → 201 (created, stored)
POST /v1/subscriptions Idempotency-Key: abc → 201 (same body, NOT charged twice)
SituationResult
Same key, same request bodyReturns the original stored response.
Same key, different body422 idempotency_error — you reused a key for a different operation.
Same key, original still in progress409 request_in_progress — retry shortly.

The body is fingerprinted (SHA-256 of method + path + canonical JSON body), so “same body” means semantically same, regardless of key ordering or whitespace.

  • Generate one key per operation and reuse it across retries of that operation. Don’t generate a fresh key on retry — that defeats the purpose.
  • Persist the key alongside the work you’re doing, so a crash-and-restart retries with the same key.
  • Don’t reuse a key for a different operation (you’ll get 422).
const key = crypto.randomUUID(); // once, before the first attempt
await withRetries(() =>
fetch(`${API}/v1/subscriptions`, {
method: "POST",
headers: {
"x-api-key": KEY,
"Idempotency-Key": key, // same key every retry
"Content-Type": "application/json",
},
body: JSON.stringify({ customerId, priceId }),
})
);

A few endpoints opt out because a stored replay would be wrong — OTP sends and multipart file uploads, for example. Those are marked in the API Reference and don’t take an Idempotency-Key. Read endpoints (GET) never need one.