> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tonder.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How Webhooks Work

Webhooks are automated messages sent from Tonder when transaction events occur. Instead of repeatedly polling our API for status changes, webhooks provide real-time notifications the moment something happens—like a payment completing, failing, or requiring additional authentication.

Using webhooks makes your integration more efficient and responsive, ensuring your system stays synchronized with transaction updates in real-time.

## Key Events

Tonder sends webhook notifications for various transaction events:

| Event Type                     | Description                                                     | Example Status Flow                        |
| ------------------------------ | --------------------------------------------------------------- | ------------------------------------------ |
| **Payment Status Changes**     | Real-time updates as payments progress through different states | `pending` → `authorized` → `success`       |
| **Payment Failures**           | Notifications when payments are declined or fail                | `pending` → `declined` or `failed`         |
| **3DS Authentication**         | Updates when users complete 3D Secure challenges                | `pending_3ds` → `success` or `failed`      |
| **Cash Payment Confirmations** | Notifications when customers pay OXXO vouchers                  | `pending` → `success` (when paid at store) |
| **Withdrawal Updates**         | Status changes for payout transactions                          | `processing` → `success` or `failed`       |

## Webhook Payload Structure

API Direct webhooks use a **flat payload** — all fields are at the top level with no nested `data` wrapper. Here are the key fields:

| Field                 | Type   | Description                                                                                  |
| --------------------- | ------ | -------------------------------------------------------------------------------------------- |
| `id`                  | string | Unique identifier for this webhook event                                                     |
| `operation_type`      | string | Type of operation (e.g., `payment`)                                                          |
| `amount`              | string | Transaction amount as a string                                                               |
| `currency`            | string | ISO 4217 currency code (e.g., `MXN`)                                                         |
| `client_reference`    | string | Your own reference ID for the transaction                                                    |
| `status`              | string | Current transaction status (e.g., `Success`, `Pending`, `Failed`)                            |
| `provider`            | string | Payment provider that processed the transaction                                              |
| `transaction_id`      | string | Tonder's internal transaction identifier                                                     |
| `payment_method_type` | string | Payment method used (e.g., `SPEI`, `CARD`, `OXXO`)                                           |
| `created`             | string | ISO 8601 timestamp of when the event was created                                             |
| `metadata`            | object | Custom key-value pairs passed when the payment was created                                   |
| `event_type`          | string | Specific event that triggered this notification (e.g., `payment_Success`, `payment_Pending`) |
| `action`              | string | Action associated with the event (e.g., `MODIFY`)                                            |

Here are examples of the two most common event types:

<CodeGroup>
  ```json payment_Success theme={null}
  {
    "id": "fc38522e-3e5d-45b8-ba6a-ece72caee71f",
    "operation_type": "payment",
    "amount": "70",
    "currency": "MXN",
    "client_reference": "f6d16280-7bff-4bb7-b6f1-967f9721248b",
    "status": "Success",
    "provider": "tonder",
    "transaction_id": "e9340a04-6d68-4afc-86c5-79f8b7c87de4",
    "payment_method_type": "SPEI",
    "created": "2026-05-21T19:15:32.029134Z",
    "metadata": {
      "order_id": "f6d16280-7bff-4bb7-b6f1-967f9721248b",
      "money_type": "rebet_cash",
      "external_id": "ec2d3598-f061-7081-11a4-a8afedce2ef7",
      "transaction_type": "deposit"
    },
    "event_type": "payment_Success",
    "action": "MODIFY"
  }
  ```

  ```json payment_Pending theme={null}
  {
    "id": "b47faf2d-844e-4f14-bedd-f998a016cacd",
    "operation_type": "payment",
    "amount": "200",
    "currency": "MXN",
    "client_reference": "a38f5292-4c5e-42cd-aa73-15763d2d4862",
    "status": "Pending",
    "provider": "tonder",
    "transaction_id": "aa15fe61-a680-40b9-8546-4a98c204dc9d",
    "payment_method_type": "SPEI",
    "created": "2026-05-21T21:27:56.220201Z",
    "metadata": {
      "order_id": "f6d16280-7bff-4bb7-b6f1-967f9721248b",
      "money_type": "rebet_cash",
      "external_id": "ec2d3598-f061-7081-11a4-a8afedce2ef7",
      "transaction_type": "deposit"
    },
    "event_type": "payment_Pending",
    "action": "MODIFY"
  }
  ```
</CodeGroup>

## Getting Started with Webhooks

To start receiving webhook notifications, you need to:

1. Create a publicly accessible HTTPS URL that can receive POST requests.
2. Secure your endpoint to verify requests come from Tonder.
3. Register your endpoint using our [API](/reference/webhooks).
4. Process incoming webhook notifications in your application.

<Note>
  Prerequisites for webhook endpoints:

  * Must use HTTPS (not HTTP) for security.
  * Should respond within 30 seconds to avoid timeouts.
  * Must return a 2xx status code to acknowledge receipt.
  * Should implement authentication to verify request source.
</Note>

## Reliability and Delivery

Tonder ensures reliable webhook delivery through built-in resilience mechanisms:

| Feature               | Details                                                            | Benefit                                               |
| --------------------- | ------------------------------------------------------------------ | ----------------------------------------------------- |
| **Automatic Retries** | Up to 3 delivery attempts with 60-second intervals between retries | Handles temporary outages and network issues          |
| **Response Timeout**  | 30-second timeout per delivery attempt                             | Prevents hanging requests and ensures timely retries  |
| **Dead Letter Queue** | Failed events stored for 30 days with manual reprocessing          | No events lost, manual recovery for persistent issues |
| **Success Criteria**  | Any 2xx HTTP status code within timeout window                     | Simple and flexible acknowledgment requirements       |

For complete details on delivery mechanisms and retry policies, see [Delivery and Retry Logic](/direct-integration/webhooks/delivery-and-retry).

## Common Use Cases

Here are practical examples showing how to implement webhook handlers for the most common scenarios you'll encounter in production applications:

<AccordionGroup>
  <Accordion title="Real-time Payment Status Updates">
    Handle payment status changes to automatically fulfill orders when payments complete or fail. Note that the API Direct payload is flat — all fields are at the top level.

    ```python theme={null}
    @app.route('/webhook', methods=['POST'])
    def handle_payment_webhook():
        payload = request.get_json()
        
        if payload['event_type'] == 'payment_Success':
            # Payment completed successfully
            fulfill_order(payload['client_reference'])
            
        elif payload['event_type'] == 'payment_Failed':
            # Payment failed
            cancel_order(payload['client_reference'])

        elif payload['event_type'] == 'payment_Pending':
            # Payment is awaiting confirmation (e.g., SPEI transfer in progress)
            mark_order_pending(payload['client_reference'])
        
        return jsonify({'status': 'received'}), 200
    ```
  </Accordion>

  <Accordion title="3DS Authentication Handling">
    Process 3D Secure authentication completions to finalize payments that required additional customer verification.

    ```python theme={null}
    @app.route('/webhook', methods=['POST'])
    def handle_3ds_webhook():
        payload = request.get_json()
        
        if payload['event_type'] == 'payment_Success':
            # 3DS authentication successful, payment completed
            complete_order(payload['client_reference'])
        elif payload['event_type'] == 'payment_Failed':
            # 3DS authentication failed
            cancel_order(payload['client_reference'])
        
        return jsonify({'status': 'received'}), 200
    ```
  </Accordion>
</AccordionGroup>

## Webhook Management

Now that you understand how webhooks work and have seen practical examples, explore these focused guides to implement webhooks in your application:

<CardGroup cols={3}>
  <Card title="Setup & Management" icon="gear" href="/direct-integration/webhooks/setup-and-managing">
    Learn how to create, configure, and manage webhook endpoints through the API
  </Card>

  <Card title="Delivery & Retry" icon="repeat" href="/direct-integration/webhooks/delivery-and-retry">
    Understand how webhooks are delivered, retry policies, and handling failures
  </Card>

  <Card title="Best Practices" icon="shield-check" href="/direct-integration/webhooks/best-practices">
    Security recommendations and implementation patterns for reliable webhooks
  </Card>
</CardGroup>
