Skip to content

Preview. The API is shared with design partners and may change before launch. Register interest for sandbox access.

Idempotency

Networks fail. To make retries safe, send an Idempotency-Key header with every POST. If Phew has already processed a request with that key, it returns the original response instead of doing the work again, so a retried POST /v1/policies never creates two policies.

POST /v1/policies HTTP/1.1
Idempotency-Key: order-100482-policy
  • Keys are up to 255 characters. Use a UUID, or derive the key from your own ID (for example the order ID) so that it’s stable across restarts.
  • Keys are scoped to your account and the merchant, and kept for 24 hours.
  • A replayed response has the header Idempotent-Replayed: true.
  • Reusing a key with a different request body returns 409 idempotency_conflict.
  • If the first request is still running, a second one with the same key returns 409 with Retry-After.
  • Only successful responses and 4xx validation errors are stored. A 5xx is not stored, so a retry runs again.

Retry on network errors, 429 and 5xx, with exponential backoff and jitter, reusing the same key:

async function withRetries<T>(call: () => Promise<Response>): Promise<Response> {
for (let attempt = 0; ; attempt++) {
const response = await call().catch(() => null);
if (response && response.status < 500 && response.status !== 429) return response;
if (attempt === 6) return response ?? Promise.reject(new Error("Phew unreachable"));
const retryAfter = Number(response?.headers.get("Retry-After")) * 1000;
const backoff = Math.min(30_000, 500 * 2 ** attempt) * (0.5 + Math.random() / 2);
await new Promise((resolve) => setTimeout(resolve, retryAfter || backoff));
}
}

For policy creation, keep retrying from a queue for up to 24 hours before treating it as failed.