Retries and long requests

Make a write safe to retry with Idempotency-Key, and run long calls in the background with Prefer respond-async.

Retry a write safely

Networks drop answers. If a POST, PUT, PATCH or DELETE times out, you can't tell whether it ran. Send an Idempotency-Key header and retry with the same key: the first answer comes back instead of the call running again.

curl -X POST https://dev.app.ingenee.ai/api/v1/titles \
  -H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
  -H "Idempotency-Key: 4f7d2c1e-import-run-118-row-42" \
  -d '{ "source": "manual", "title": "The Long Road", "year": 2019, "type": "movie" }'
  • The key is any string of 1 to 255 visible ASCII characters. A UUID per logical operation works well.
  • A replayed answer has the same status and body as the first, plus the header idempotent-replayed: true.
  • Keys belong to one API key and are kept 24 hours. After that the same key runs the call again.
  • The same key on a different request (another path, query or body) is refused with 422 IDEMPOTENCY_KEY_REUSED.
  • While the first call is still running, a retry gets 409 REQUEST_IN_PROGRESS. Wait and retry.
  • A 5xx answer is not kept, so a retry after a server error runs again.
  • GET calls ignore the header; they are safe to repeat anyway.

Run a long call in the background

A few calls can run for a long time: generating or extending a schedule, and re-running enrichment. Their reference pages say Send Prefer: respond-async. With that header the call answers 202 Accepted at once:

curl -i -X POST https://dev.app.ingenee.ai/api/v1/channels/f27a91c3-4b6d-4e08-a5d2-9c1e3b7f0a64/schedule/generate \
  -H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
  -H "Prefer: respond-async" -d '{}'
202 Accepted
location: /v1/requests/9a0f5d3c-2b1e-4c7a-8f6d-1e2d3c4b5a69
preference-applied: respond-async

{ "id": "9a0f5d3c-2b1e-4c7a-8f6d-1e2d3c4b5a69", "status": "running", "poll": "/v1/requests/9a0f5d3c-2b1e-4c7a-8f6d-1e2d3c4b5a69" }

Poll GET /v1/requests/{id} every few seconds:

200 OK
{
  "id": "9a0f5d3c-2b1e-4c7a-8f6d-1e2d3c4b5a69",
  "operation": "generateSchedule",
  "status": "done",
  "createdAt": "2026-10-30T12:01:04.120Z",
  "completedAt": "2026-10-30T12:02:51.733Z",
  "response": { "status": 201, "body": { "versionId": "…", "versionNum": 7, "itemCount": 412 } }
}

While status is running, response is null. When it is done, response is exactly what the call would have returned, error or not: check response.status.

  • Only the API key that made the request can read it. Any other key gets 404.
  • Results are kept 24 hours.
  • Prefer: respond-async on a call that doesn't support it is ignored, and the call runs normally.
  • Combine both headers to make a background call safe to retry: a retry with the same Idempotency-Key returns the same request id while it runs, then its result.

On this page