When integrating with Cashfree Payment Gateway, it’s crucial to implement webhook idempotency to ensure your application processes only final and unique payment events. Below are the core principles and practices to follow.

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 unique cf_payment_id.
  • Unique payment_id per attempt: Every retry—whether triggered by the user or automatically—will have a distinct cf_payment_id but the same order_id.
  • Terminal status: Only consider webhook events where payment_status = SUCCESS as 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 payment_id: Track cf_payment_id in your database and ensure it is processed 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_id matches the one you created.
    • The payment_status is SUCCESS.
    • The order has not already been marked as paid.
  • 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 the SUCCESS webhook.
  • Ignore duplicate FAILED webhooks: Webhook events with a FAILED status 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_id for a given order_id to support reporting, reconciliation, or dispute management.
Do not mark the order as PAID on receiving FAILED or PENDING statuses. Always wait for a SUCCESS webhook before finalising the payment status.