Webhooks Handling


PhonePe Payment Gateway uses Webhook (S2S Callbacks) to notify you about key events like payment completion or refund status. Here’s how it works:

  • You need to provide a Webhook URL (a specific endpoint on your server) where these updates will be sent.
  • To ensure secure communication, you should set up a username and password for authentication.
  • Configure Webhook: Follow these steps to set up a new webhook for receiving event notifications.
    • Log in to your PhonePe Business Dashboard.
    • Set the environment mode using the Test Mode toggle located on the dashboard.
      • For Sandbox (Testing): Ensure the toggle is switched ON.
      • For Production (Live): Ensure the toggle is switched OFF.
    • Navigate to Developer Settings from the side menu.
    • Select the Webhook tab and click the Create Webhook button.
    • In the configuration form, fill in the following details:
      • Webhook URL: Your server’s endpoint URL to receive notifications.
      • Username: Your authentication username.
      • Password: Your authentication password.
      • Description: A brief description for your reference.
    • From the list of active events, choose:
      • Order Events:
        • pg.order.completed: Sent when an order is successfully completed
        • pg.order.failed: Sent when an order fails
      • Refund Events:
        • pg.refund.completed: Sent when a refund is successfully processed
        • pg.refund.failed: Sent when a refund processing fails
    • Click Create to save and complete the configuration.
    • Your webhook is now active.
  • Authorization.
    • Once configured, PhonePe Payment Gateway will send updates to your server using the provided username and password.
    • These credentials will be used to create an Authorization header in the webhook response using SHA256 (username:password) method.
  • Verification.
    • For the incoming request, extract the header Authorization, verify it with the one which you have shared with us and accept the response if the Username and password match.
    • If the hash matches the one sent by PhonePe Payment Gateway, the update is valid, and the response payload can be consumed.
    • If it doesn’t match, the response should be ignored.
  • Order Events:
    • pg.order.completed: Sent when an order is successfully completed
    • pg.order.failed: Sent when an order fails
  • Refund Events:
    • pg.refund.completed: Sent when a refund is successfully processed
    • pg.refund.failed: Sent when a refund processing fails

ℹ️ Authorization Header!


PhonePe Payment Gateway includes the Authorization header in the following format:
Authorization: SHA256(username:password)

  • For the incoming request, extract the basic authorization header “Authorization”, verify it with the one which you have shared with us and accept the response if Username and password matches.
  • Use the “payload.state” Parameter: For payment status, rely only on the root-level “payload.state” field in the response
  • Avoid Strict Deserialization: Don’t use overly strict rules for processing the response
  • Use the “event” Parameter: Ignore the “type” parameter in the webhook response. Use the “event” parameter instead to identify the event type
  • Time Format: The expireAt and timestamp fields will be in epoch time
Sample Response of Order Completed
{
  "type": "PG_ORDER_COMPLETED",
  "event": "pg.order.completed",
  "payload": {
    "merchantId": "AIRTELUAT",
    "merchantOrderId": "MO-974-9c0084d009a8",
    "orderId": "OMO2411281510176245053157",
    "state": "COMPLETED",
    "amount": 100,
    "expireAt": 1732959621335,
    "metaInfo": {
      "udf5": "<additional-information-5>",
      "udf3": "<additional-information-3>",
      "udf4": "<additional-information-4>",
      "udf1": "<additional-information-1>",
      "udf2": "<additional-information-2>"
    },
    "paymentDetails": [
      {
        "paymentMode": "UPI_INTENT",
        "transactionId": "OM2411281510213355053368",
        "timestamp": 1732786838930,
        "amount": 100,
        "state": "COMPLETED",
        "splitInstruments": [
          {
            "amount": "100",
            "rail": {
              "type": "UPI",
              "utr": "<utr>",
              "upiTransactionId": "<upiTransactionId>",
              "vpa": "<vpa>"
            },
            "instrument": {
              "type": "ACCOUNT",
              "maskedAccountNumber": "<maskedAccountNumber>",
              "accountType": "SAVINGS",
              "accountHolderName": "<accountHolderName>",
              "ifsc": "<ifsc>"
            }
          }
        ]
      }
    ]
  }
}
Sample Response of Order Failed
{
    "type": "PG_ORDER_FAILED",
    "event": "pg.order.failed",
    "payload": {
        "merchantId": "AIRTELUAT",
        "merchantOrderId": "MO-c68-9f96cc57a7e8",
        "orderId": "OMO2411281511242605053174",
        "state": "FAILED",
        "amount": 100,
        "errorCode": "AUTHORIZATION_ERROR",
        "detailedErrorCode": "ZM",
        "expireAt": 1732959688009,
        "metaInfo": {
            "udf5": "<additional-information-5>",
            "udf3": "<additional-information-3>",
            "udf4": "<additional-information-4>",
            "udf1": "<additional-information-1>",
            "udf2": "<additional-information-2>"
        },
        "paymentDetails": [
            {
                "paymentMode": "UPI_INTENT",
                "transactionId": "OM2411281511280095053516",
                "timestamp": 1732786903141,
                "amount": 100,
                "state": "FAILED",
                "errorCode": "AUTHORIZATION_ERROR",
                "detailedErrorCode": "ZM",
                "splitInstruments": [
                    {
                        "amount": "100",
                        "rail": {
                            "type": "UPI",
                            "upiTransactionId": "<upiTransactionId>"
                        },
                        "instrument": {
                            "type": "ACCOUNT",
                            "maskedAccountNumber": "<maskedAccountNumber>",
                            "accountType": "SAVINGS",
                            "accountHolderName": "<accountHolderName>",
                            "ifsc": "<ifsc>"
                        }
                    }
                ]
            }
        ]
    }
}
Sample Response of Refund Completed for Case 1: Original source of transaction = UPI
{
    "event": "pg.refund.completed",
    "payload": {
        "merchantId": "merchantId",
        "merchantRefundId": "merchantRefundId",
        "originalMerchantOrderId": "Refund-12345",
        "amount": 50000,
        "state": "COMPLETED",
        "timestamp": 1706629419799,
        "refundId": "OMR7896789",
        "splitInstruments": [
            {
                "rail": {
                    "type": "UPI",
                    "upiTransactionId": "upi12313",
                    "vpa": "12****78@ybl"
                },
                "instrument": {
                    "type": "ACCOUNT",
                    "accountType": "SAVINGS",
                    "maskedAccountNumber": "******1234"
                },
                "amount": 40000
            },
            {
                "rail": {
                    "type": "WALLET"
                },
                "instrument": {
                    "type": "WALLET",
                    "walletId": "ABCD"
                },
                "amount": 10000
            }
        ]
    }
}
Sample Response of Refund Completed for Case 2: Original source of transaction = CARD
{
    "event": "pg.refund.completed",
    "payload": {
        "merchantId": "merchantId",
        "merchantRefundId": "merchantRefundId",
        "originalMerchantOrderId": "Refund-12345",
        "amount": 50000,
        "state": "COMPLETED",
        "timestamp": 1706629419799,
        "refundId": "OMR7896789",
        "splitInstruments": [
            {
                "amount": 50000,
                "rail": {
                    "type": "PG",
                    "transactionId": "transactionId",
                    "authorizationCode": "authorizationCode",
                    "serviceTransactionId": "serviceTransactionId"
                },
                "instrument": {
                    "type": "CREDIT_CARD",
                    "bankTransactionId": "bankTransactionId",
                    "bankId": "bankId",
                    "arn": "arn",
                    "brn": "brn"
                }
            }
        ]
    }
}
Sample Response of Refund Completed for Case 3: Original source of transaction = NET_BANKING
{
    "event": "pg.refund.completed",
    "payload": {
        "merchantId": "merchantId",
        "merchantRefundId": "merchantRefundId",
        "originalMerchantOrderId": "Refund-12345",
        "amount": 50000,
        "state": "COMPLETED",
        "timestamp": 1706629419799,
        "refundId": "OMR7896789",
        "splitInstruments": [
            {
                "amount": 50000,
                "rail": {
                    "type": "PG",
                    "transactionId": "transactionId",
                    "authorizationCode": "authorizationCode",
                    "serviceTransactionId": "serviceTransactionId"
                },
                "instrument": {
                    "type": "NET_BANKING",
                    "bankTransactionId": "bankTransactionId",
                    "bankId": "bankId>",
                    "arn": "arn",
                    "brn": "brn"
                }
            }
        ]
    }
}
Sample Response of Refund Failed for Case 1: Original source of transaction = UPI
{
    "event": "pg.refund.failed",
    "payload": {
        "merchantId": "merchantId",
        "merchantRefundId": "merchantRefundId",
        "originalMerchantOrderId": "Refund-12345",
        "amount": 50000,
        "state": "FAILED",
        "timestamp": 1706629419799,
        "refundId": "OMR7896789",
        "errorCode": "UPI_BACKBONE_ERROR",	// Only present in case of ERROR
        "detailedErrorCode": "UPI_1231",	// Only present in case of ERROR
        "splitInstruments": [				// In case of failure this is optional. It may or may not be present.
            {
                "rail": {
                    "type": "UPI",
                    "upiTransactionId": "upi12313",
                    "vpa": "12****78@ybl"
                },
                "instrument": {
                    "type": "ACCOUNT",
                    "accountType": "SAVINGS",
                    "maskedAccountNumber": "******1234"
                },
                "amount": 40000
            },
            {
                "rail": {
                    "type": "WALLET"
                },
                "instrument": {
                    "type": "WALLET",
                    "walletId": "ABCD"
                },
                "amount": 10000
            }
        ]
    }
}
Sample Response of Refund Failed for Case 2: Original source of transaction = CARD
{
    "event": "pg.refund.failed",
    "payload": {
        "merchantId": "merchantId",
        "merchantRefundId": "merchantRefundId",
        "originalMerchantOrderId": "Refund-12345",
        "amount": 50000,
        "state": "FAILED",
        "timestamp": 1706629419799,
        "refundId": "OMR7896789",
        "errorCode": "PG_BACKBONE_ERROR",	// Only present in case of ERROR
        "detailedErrorCode": "UPI_1231",	// Only present in case of ERROR
        "splitInstruments": [				// In case of failure this is optional. It may or may not be present.
            {
                "amount": 50000,
                "rail": {
                    "type": "PG",
                    "transactionId": "transactionId",
                    "authorizationCode": "authorizationCode",
                    "serviceTransactionId": "serviceTransactionId"
                },
                "instrument": {
                    "type": "CREDIT_CARD",
                    "bankTransactionId": "bankTransactionId",
                    "bankId": "bankId",
                    "arn": "arn",
                    "brn": "brn"
                }
            }
        ]
    }
}
Sample Response of Refund Failed for Case 3: Original source of transaction = NET_BANKING
{
    "event": "pg.refund.failed",
    "payload": {
        "merchantId": "merchantId",
        "merchantRefundId": "merchantRefundId",
        "originalMerchantOrderId": "Refund-12345",
        "amount": 50000,
        "state": "FAILED",
        "timestamp": 1706629419799,
        "refundId": "OMR7896789",
        "errorCode": "PG_BACKBONE_ERROR",	// Only present in case of ERROR
        "detailedErrorCode": "UPI_1231",	// Only present in case of ERROR
        "splitInstruments": [				// In case of failure this is optional. It may or may not be present.
            {
                "amount": 50000,
                "rail": {
                    "type": "PG",
                    "transactionId": "transactionId",
                    "authorizationCode": "authorizationCode",
                    "serviceTransactionId": "serviceTransactionId"
                },
                "instrument": {
                    "type": "NET_BANKING",
                    "bankTransactionId": "bankTransactionId",
                    "bankId": "bankId",
                    "arn": "arn",
                    "brn": "brn"
                }
            }
        ]
    }

In the next section, you will learn how to initiate a refund. This action is required when you need to return funds to a customer for a previously successful transaction, such as for a returned item or a cancelled order.

Is this article helpful?