> For the complete documentation index, see [llms.txt](https://docs.hyperswitch.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hyperswitch.io/integration-guide/webhooks.md).

# Webhooks

Configure outgoing webhooks from Hyperswitch

Webhooks let Hyperswitch send event updates to your server without polling. Each delivery is an HTTP `POST` with a JSON body.

Webhooks in Hyperswitch run in two directions, and this guide covers both:

* **Incoming webhooks** (also called callbacks): the connector (the payment processor) calls Hyperswitch when something happens, such as a payment succeeding. Hyperswitch verifies the callback and updates the matching resource (a payment, refund, or dispute). If you have a webhook endpoint configured, Hyperswitch then sends you the outgoing webhook.
* **Outgoing webhooks**: Hyperswitch calls your server with the event. Everything under [Handling webhooks](#handling-webhooks) describes this direction.

### Webhook flows and webhook support

Connector pages state two separate facts, and they do not always agree:

* **Webhooks implemented**: whether Hyperswitch can process the connector's callbacks. This is about the code: whether the connector verifies signatures, identifies which payment the callback is about, and maps the event. If webhooks are not implemented, Hyperswitch cannot process callbacks or update payment status from them, so you must poll (use payment sync).
* **Webhook flows**: a category list (payments, refunds, disputes, and so on) that the connector's code declares. It says which kinds of events the connector's webhooks are expected to cover. Hyperswitch does not use this list to accept or reject callbacks; it exists for reporting, and each connector page shows it.

A connector can have webhooks working but no declared flows. Its connector page then says something like "Webhook flows: None declared in code" while the Webhooks section on the same page describes working webhooks. The flows list is a declaration that the connector's author fills in, and it can lag behind the code. Treat the Webhooks section of the connector page, not the flows line, as the statement of what actually works.

### Configuring webhooks

#### Create an endpoint on your server

Create a public HTTPS endpoint that accepts `POST` requests. Return a `2xx` status only after your application has accepted the event for processing.

#### Configure your webhook endpoint on Hyperswitch Dashboard

1. Select the business profile and mode that the endpoint belongs to.
2. Go to **Developers → Payment Settings → Payment Behaviour**.
3. Add the endpoint URL.
4. In live mode, ask the Hyperswitch team to allowlist the URL.
5. Save the setting. After your payment flow can produce an event, send a test payment and confirm that your endpoint responds.

These steps follow the [Control Center developers guide](/integration-guide/control-center/developers.md#setting-up-a-webhook).

#### Update Hyperswitch's webhook endpoints on your connector dashboard

This step applies after the connector account exists. Register the connector webhook with:

```http
POST /account/{account_id}/webhooks/{merchant_connector_id}
```

The path parameters are the merchant account ID and merchant connector ID. The request configures the webhook at the connector for that existing account.

### Handling webhooks

The v1 API schema defines 33 event wire values:

1. `payment_succeeded`
2. `payment_failed`
3. `payment_processing`
4. `payment_cancelled`
5. `payment_cancelled_post_capture`
6. `payment_authorized`
7. `payment_partially_authorized`
8. `payment_captured`
9. `payment_expired`
10. `action_required`
11. `refund_succeeded`
12. `refund_failed`
13. `refund_review`
14. `dispute_opened`
15. `dispute_expired`
16. `dispute_accepted`
17. `dispute_cancelled`
18. `dispute_challenged`
19. `dispute_won`
20. `dispute_lost`
21. `mandate_active`
22. `mandate_revoked`
23. `payout_success`
24. `payout_failed`
25. `payout_initiated`
26. `payout_processing`
27. `payout_cancelled`
28. `payout_expired`
29. `payout_reversed`
30. `payout_not_permitted`
31. `invoice_paid`
32. `surcharge_payment_succeeded`
33. `surcharge_refund_succeeded`

The outgoing webhook object has 6 fields. `merchant_id`, `event_id`, `event_type`, and `content` are required. `timestamp` and `processor_merchant_id` are optional; the schema marks `processor_merchant_id` as nullable.

The `content` object has 6 wire shapes. Its `type` is one of `payment_details`, `refund_details`, `dispute_details`, `mandate_details`, `payout_details`, or `subscription_details`. The matching resource is in `content.object`.

See the [outgoing webhook schema](https://api-reference.hyperswitch.io/v1/schemas/outgoing--webhook) for each resource shape.

### Webhook signature verification

Set `payment_response_hash_key` on the business profile and store it securely. Hyperswitch signs the serialized webhook body with HMAC-SHA512 and sends the hex-encoded digest in `X-Webhook-Signature-512`.

#### Webhook signature generation

Hyperswitch generates the signature from the exact serialized JSON body and `payment_response_hash_key`. Any byte-level change to the body changes the digest.

#### Webhook validation

1. Read the raw request body before parsing it.
2. Read `X-Webhook-Signature-512`.
3. Generate an HMAC-SHA512 digest from the raw body with `payment_response_hash_key`.
4. Hex-encode the digest.
5. Compare the generated and received values in constant time.
6. Reject the delivery if they do not match.

#### Troubleshooting signature verification failures

* **Signature does not match:** use the raw request bytes, not JSON that your application parsed and serialized again.
* **Header is missing:** check `X-Webhook-Signature-512` and confirm that the business profile has `payment_response_hash_key` configured.
* **Digest format differs:** compare the hex-encoded HMAC-SHA512 digest.

### Webhook delivery behavior

A delivery succeeds when your endpoint returns a `2xx` response. The scheduler makes 16 retries over roughly 24 hours: the first fires 1 minute after the original attempt (`start_after`), then the configured frequency groups apply as delays between retries.

| Retry attempt     | Delay                               |
| ----------------- | ----------------------------------- |
| 1st               | 1 minute after the original attempt |
| 2nd and 3rd       | 5 minutes                           |
| 4th through 8th   | 10 minutes                          |
| 9th through 13th  | 1 hour                              |
| 14th through 16th | 6 hours                             |

#### Handling duplicates

Retries can deliver the same event more than once. Store the required `event_id` and make event processing idempotent. If an `event_id` has already completed, acknowledge the duplicate without applying the change again.

#### Handling out-of-order deliveries

Do not assume that delivery order matches event order. For payment webhooks, compare `content.object.updated` with the value already stored and apply only the newer payment state. The v1 schema does not define `updated` on every other webhook resource shape, so handle their ordering with fields from the matching resource schema.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hyperswitch.io/integration-guide/webhooks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
