Key concepts
The following are the key concepts:-
Multiple payment attempts per order_id: For a single
order_id, Cashfree allows multiple payment attempts until one succeeds. Each attempt generates a uniquecf_payment_id. -
Unique payment_id per attempt: Every retry—whether triggered by the user or automatically—will have a distinct
cf_payment_idbut the sameorder_id. -
Terminal status: Only consider webhook events where
payment_status = SUCCESSas the final confirmation of payment for an order.
Statuses such as
FAILED, NOT_ATTEMPTED, or PENDING are transitional and should not be treated as final.
Webhook idempotency flowchart
Best practices
The following are the recommended best practices:-
De-duplicate using cf_payment_id: Track
cf_payment_idin your database and process each payment only once, regardless of how many webhook retries you receive. -
Order-level validation: Update the order status only when you receive a webhook that meets all of the following conditions:
- The
order_idmatches the one you created. - The
payment_statusisSUCCESS. - The order has not already been marked as paid.
- The
-
Handle retried payments: Users may retry failed payments. As a result, you may receive multiple webhook events in the sequence:
FAILED → PENDING → SUCCESS.
Implement logic to update the order status only upon receiving theSUCCESSwebhook. -
Ignore duplicate FAILED webhooks: Webhook events with a
FAILEDstatus may be sent multiple times. Do not trigger any final actions for these statuses unless you are tracking them for logging or metrics. -
Store payment attempts: Keep a log of all
cf_payment_idfor a givenorder_idto support reporting, reconciliation, or dispute management. - Use HTTPS endpoints: Your webhook URL must be publicly reachable from Cashfree. Production endpoints must use HTTPS.
- Respond immediately: Your endpoint must return a successful HTTP 200 response immediately after receiving the webhook payload.
-
Verify signatures: Verify the webhook signature using the
x-webhook-signatureheader before processing the payload to authenticate the request. For implementation details, see Webhook signature verification.
Do not mark the order as PAID on receiving
FAILED or PENDING statuses.
Always wait for a SUCCESS webhook before finalising the payment status.