6. Idempotency
Idempotency is implemented per endpoint, not globally. The table is the authoritative summary; section 11 repeats the detail for each endpoint.
| Endpoint | Key location | Required | Replay behaviour | Conflict behaviour |
|---|---|---|---|---|
POST /finance/transactions | Body field idempotencyKey (16 to 128 chars) | Yes (schema) | Same key and same fingerprint: returns the existing transaction with status 201 | Same key, different fingerprint: 409 IDEMPOTENCY_CONFLICT |
POST /finance/transactions/{id}/reversal and /refund | Body field idempotencyKey | Yes (schema) | Same key and fingerprint: returns the existing correction | Different fingerprint: 409 IDEMPOTENCY_CONFLICT |
POST /finance/transactions/{id}/approve, /reject | None | n/a | Not idempotent. A second call finds the transaction no longer pending: 409 INVALID_STATE | n/a |
POST /finance-applications | Header Idempotency-Key (8 to 128 chars, [A-Za-z0-9._:-]) | Yes | Same key and fingerprint: returns the existing application (201) | Different fingerprint: 409 IDEMPOTENCY_CONFLICT |
POST /finance-applications/{id}/transition | Header | Yes | Same key: returns the current application. No fingerprint comparison. | n/a |
POST /finance-applications/{id}/decision | Header | Yes | Same key: returns the current application. No fingerprint comparison. | n/a |
POST /financing-cases | Header | Yes | Same key: returns the existing case. No fingerprint comparison. | n/a |
POST /financing-cases/{id}/transition | Header | Yes | Same key: returns the existing transition record. | n/a |
POST /financing-cases/{id}/agreements | Header | Yes | Same key: returns the existing agreement. | n/a |
POST /{resource} (generic) | None read | n/a | Not implemented. A duplicate natural key returns 409 CONFLICT | n/a |
PATCH /{resource} (generic) | None | n/a | Not applicable | n/a |
POST /reconciliation/sync | None | n/a | Not idempotent: every call queues a new job | n/a |
POST /reporting/jobs | None | n/a | Not idempotent: every call queues a new job | n/a |
POST /marketplace/applications/{id}/decision | None | n/a | Second call finds the request decided: 409 INVALID_STATE | n/a |
POST /webhooks/{provider} | Provider event id | n/a | Duplicate (tenant, provider, eventId): returns 200 with duplicate: true | n/a |
POST /contact | None | n/a | Not idempotent | n/a |
Header name used by the code is Idempotency-Key. Send 16 to 128 characters (A-Z a-z 0-9 . _ : -).