Which errors to retry
internal_error can be deterministic, so a blind retry can loop on the same failure. Retry a publish only when it carries an idempotency_key; without one you risk storing the message twice.
Backing off
retry_after_ms and the RFC 9110 Retry-After header carry the same hint. Either one wins over whatever schedule your client uses.
When the server sends no hint, back off exponentially with jitter, cap the delay, and stop after a small number of attempts. Cap any hint you honour, server-supplied or not, so a bad value cannot park a request for hours.
Correlating a failure
Every response, success or failure, carries anX-Request-Id header. Error bodies repeat the same value as request_id so it survives client-side logging that drops headers.
Log request_id on every failure and quote it to support. It pivots directly to the corresponding server log line.
Inbound X-Request-Id headers are ignored; the server assigns the value. Send X-Amzn-Trace-Id and its Root= segment becomes the request id, so upstream trace correlation works without translation.
Malformed requests fail loudly
Request bodies decode strictly. Each of these returns400 invalid_request:
- An empty body, or a body that is not valid JSON
- A field this API does not define, including a misspelled one
- Trailing content after the first JSON value
{"namesapce": "articles"} fails immediately instead of silently falling back to a default that does not exist.
Checking a query before you send it
POST /v1/lint reports the same query problems as diagnostics with "valid": false and a 200, needs no API key, and embeds nothing. It is the cheap way to check a generated query before spending a request on it.
