Idempotency
All AstroWay API endpoints are naturally idempotent: same input always produces same output, no side effects (except credit consumption and usage logging).
This means retrying on network errors is safe. But to ensure a retry doesn’t charge credits twice, pass an Idempotency-Key header.
How to use
Section titled “How to use”POST /v1/chart HTTP/1.1X-Api-Key: aw_live_...Idempotency-Key: 01HXY2A7ZM0ABCDEFContent-Type: application/json
{ "date": "1990-07-14", "time": "14:30:00", ... }Idempotency-Key - a string of 1-255 visible ASCII characters with no spaces, unique per logical operation. Recommended: ULID or UUID v4. Our SDKs add a key to every POST themselves and keep it across their own retries.
The key applies to POST, PUT and PATCH and belongs to your API key: another API key sending the same Idempotency-Key never sees your response. Endpoints whose response can carry a secret ignore the header: key and account management (/keys, /site-keys, /auth/*, /me), webhook subscriptions (/webhooks/*), OAuth (/oauth/*) and payments (/payments/*). On any other endpoint, a response that contains a credential field (api_key, signing_secret, token and the like) is not stored either, and the key is freed.
Guarantees
Section titled “Guarantees”- For 24 hours after the first request, a repeat with the same key, method, path, body and query string returns the stored response (same status,
Content-Typeand body) without recalculation and without charging credits. The body is compared after JSON parsing, so field order and whitespace do not matter. - The replayed response carries
Idempotent-Replayed: true,X-Credits-Used: 0andIdempotent-Original-Credits-Usedwith the price of the first request. - 24 hours after the first request the key is forgotten; a new request with the same key is treated as a normal new request.
A replay goes through the same key check and the same rate limit as any request: a revoked key gets 401, not the stored response.
Errors
Section titled “Errors”| Status | Code | When |
|---|---|---|
400 | INVALID_IDEMPOTENCY_KEY | the key is empty, longer than 255 characters, contains a space or a non-ASCII character, or the header was sent twice |
409 | IDEMPOTENCY_KEY_REUSED | the key was already used with a different body or query string. A new request needs a new key |
409 | IDEMPOTENCY_IN_PROGRESS | the first request with this key is still running. The response carries Retry-After: 1; retry and you get its result |
None of these responses is charged.
What is stored and what is not
Section titled “What is stored and what is not”- Only a successful (2xx) response. An error (
4xx,5xx) is not charged and not remembered, so after one you can retry with the same key, including with a corrected body. - A dropped connection. If the client disconnects before the response is complete, the request is not charged and the key is freed for the retry.
- Streamed (SSE) and binary responses are stored whole and replayed as one body with the same
Content-Type. A stream whose last event is an error (type: "error") is not stored even though its status is200, and the key is freed for a retry. Such a stream is not charged, although theX-Credits-Usedheader, sent before the stream began, shows the price of the call. - A response over 1 MB is not stored, and the key is released. A repeat with the same key is a new request and is charged like one.
- If the key store is unavailable, the request is processed as if no key had been sent: you get a response rather than a
500, but a retry during that time may be charged again.
When you need it
Section titled “When you need it”- In webhook handlers where retries come from an external system (e.g. a payment provider or CRM sending events you parse and use for a calculation)
- In background jobs where retry is standard behavior on failures
- In CI/CD pipelines where a test may run multiple times
For normal “user clicks a button → show a chart” flows, idempotency isn’t needed - the user sees the result anyway, repeat clicks are rare.
When not to use
Section titled “When not to use”- Don’t set the key to save credits on identical requests: use
X-Cachefor that (free, 5 minutes) - Don’t generate the key from
hash(body): different requests would then never get a409, and a bug that sends the wrong body would go unnoticed