Idempotency and error handling

Certification cases for idempotency keys, timeouts, order recovery, error responses, and response handling rules.

Part of the Certification guide. Mark your scope on that page before you run these cases. Base payloads and test cards are on the Reference page.


11. Idempotency, timeouts, and order recovery

Applies to: CORE. idempotencyKey is a GUID in the JSON body and is required on /evaluate and /capture. A completed response is replayed for 24 hours. Persist the key before you send the request, so a crash does not lose it. Generate a new key for a merchant orderId only after GET /v1/orders?query={merchant orderId} confirms that no order exists.

Reference: Workflows §3, Idempotency reference, GET /orders/{id}, GET /orders, Appendix C.2.

IDScenarioSetup / actionExpected resultEvidence
IDEMPOTENCY-01Replay within 24 hoursSend the base CIT payload with key K1; send it again with K1Both responses are identical; GET /v1/orders?query={merchant orderId} returns exactly 1 orderBoth responses, order count
IDEMPOTENCY-02Same key, different payloadSend K1 again with a different transaction.amountHTTP 409; no new ordertraceId
IDEMPOTENCY-03Concurrent duplicateSend two identical requests with key K2 at the same timeOne returns HTTP 200; the other returns HTTP 409 with the message request already in progress, retry shortly; 1 order existsBoth responses
IDEMPOTENCY-04Key missing or not a GUIDBase CIT payload with idempotencyKey omitted, then with idempotencyKey order-123HTTP 400 both times with an errors object naming idempotencyKeytraceId
IDEMPOTENCY-05Client timeout, then retry with the same keySet your client read timeout below the sandbox response time (for example 100 ms), send the base CIT payload with key K3, observe the timeout, restore the timeout, and resend with K3The resend returns HTTP 200 with the outcome of the first request; 1 order existsResponse, order count
IDEMPOTENCY-06Recover the orderId by external order IDAfter IDEMPOTENCY-05, GET /v1/orders?query={merchant orderId}The matching order is returned with its FlexFactor orderId, status, and statusNameResponse
IDEMPOTENCY-07Order inquiry by FlexFactor orderIdGET /v1/orders/{orderId} for an order from Section 3 or Section 5HTTP 200; numeric status and statusName match the table in Appendix C.2Response
IDEMPOTENCY-08Inquiry for an unknown orderGET /v1/orders/{random GUID}HTTP 404HTTP status

12. Error handling

Applies to: CORE. Section 12.1 holds the error responses the sandbox can produce on request. Section 12.2 lists the responses the sandbox cannot force and the handling each one requires.

Reference: Error handling, Workflows §5, Appendix C.4.

12.1 Error responses

IDScenarioSetup / actionExpected resultEvidence
ERROR-01Validation error shapeBase CIT payload with transaction.amount 0HTTP 400; body has status, title, traceId, and an errors object keyed transaction.amounttraceId
ERROR-02Wrong MIDBase CIT payload with a MID that does not belong to your credentialsHTTP 403 or 400; no order createdtraceId

12.2 Response handling rules

The sandbox cannot force these responses. For each rule, state in one sentence how your integration behaves when it receives the response. The Solutions engineer accepts the written statement as evidence; no logs or code excerpts are required.

IDResponseRequired handling
HANDLE-01Any HTTP 200The decision keys on status. result is read on /evaluate only. HTTP 200 alone never marks an order paid, captured, refunded, or cancelled
HANDLE-02/evaluate HTTP 200 with result Failed, success false, and status DECLINEDThe evaluation did not complete. The merchant receives the original decline. No FlexFactor decision is recorded, and the request is not retried with a new idempotencyKey
HANDLE-03/capture HTTP 200 with status FAILED and success trueThe funds were not captured. The order is not marked paid and stays Capturerequired until the capture window elapses
HANDLE-04/refund HTTP 200 with status FAILED and success falseThe refund is not marked complete. A processor decline (responseCode and responseMessage populated) is retried under the same key. An unexpected failure (REFUND_FAILED in errors) is not retried under a new key until GET /v1/orders/{id} confirms that refundsAmount does not already include it
HANDLE-05/cancel HTTP 200The order is marked cancelled only after GET /v1/orders/{id} returns status 2 or order.cancelled arrives
HANDLE-06HTTP 400, or HTTP 409 from a reused keyThe request is not retried. The traceId is logged and the merchant receives the original decline. A reused key is a client defect and raises an alert
HANDLE-07HTTP 409 with request already in progress, retry shortlyThe same request and key are resent after a backoff of at least 2 seconds
HANDLE-08HTTP 500, 502, or 504The same request and key are retried with exponential backoff, at most 3 attempts. When a 500 repeats on the same key, automatic retries stop, an alert is raised, and the order is resolved through GET /v1/orders
HANDLE-09HTTP 503When the response carries Retry-After, the same request and key are resent after the header value. Otherwise the merchant receives the original decline and the request is not retried
HANDLE-10No response (connection failure or client timeout)The merchant receives the original decline within the merchant decision window. The order is recovered as in IDEMPOTENCY-05 and IDEMPOTENCY-06, and a new key is generated only when no order exists


Did this page help you?