# Webhooks (/webhooks)



Webhooks notify your server about changes in your Tapaya organization. Use the same integration for In-Store and Online payments, regardless of the payment processor.

## How it works [#how-it-works]

<WebhookLifecycle senderLabel="Tapaya" receiverLabel="Your server" label="A committed change queues an event. Tapaya signs and sends it. Your receiver verifies and stores it. A 2xx response confirms delivery; failures retry from the send step, up to 12 attempts, then stop." event="Saved change" queue="Queued event" send="Signed POST" receive="Verify and store" delivered="Delivered" />

Configure one HTTPS destination per organization and select the events you need. Tapaya sends an HTTP `POST` with a JSON snapshot and a signature. Verify the signature, store the event, and return a successful response before processing your business logic.

You can subscribe to individual types or all supported types. An all-types subscription also receives newly supported types in the future, so ignore types your application does not recognize.

## Quick integration [#quick-integration]

<div className="fd-steps [&_h3]:fd-step">
  ### Save a destination [#save-a-destination]

  In the Platform, open **API Keys**, then **Webhooks**. Enter your HTTPS URL, choose the events you need, and save. Copy the signing secret now; it is shown only once. See [Configuration](/webhooks/configuration).

  ### Verify each request [#verify-each-request]

  Compute an HMAC-SHA256 of the timestamp, a period, and the raw body with your signing secret, and compare it with `X-Tapaya-Signature`. See [Check the signature](/webhooks/receiving#check-the-signature).

  ### Store the event, then return 2xx [#store-the-event-then-return-2xx]

  Save the event with a unique `id`, answer `2xx` within 10 seconds, and process it afterwards. See [Store and acknowledge](/webhooks/receiving#store-and-acknowledge).

  ### Send a test webhook [#send-a-test-webhook]

  On the same page, use the test action to send a signed `webhook.test`. See [Send a test webhook](/webhooks/receiving#send-a-test-webhook).
</div>

## Event envelope [#event-envelope]

Each event uses this shared structure. The resource snapshot inside `data` depends on its type.

```json
{
  "id": "019a0000-0000-7000-8000-000000000001",
  "type": "payment.succeeded",
  "apiVersion": "1",
  "organizationId": "019a0000-0000-7000-8000-000000000002",
  "merchantId": "019a0000-0000-7000-8000-000000000005",
  "createdAt": "2026-10-30T12:00:00.000000Z",
  "data": {
    "payment": {
      "id": "019a0000-0000-7000-8000-000000000003",
      "token": "example_payment_token",
      "merchantId": "019a0000-0000-7000-8000-000000000005",
      "status": "success",
      "statusId": 2,
      "requestedAmount": 10000,
      "requestedCurrencyId": 203,
      "settlementAmount": 10000,
      "settlementCurrencyId": 203
    }
  }
}
```

| Field            | Meaning                                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `id`             | Unique event ID. Use it to deduplicate deliveries. Retries keep the same ID.                                      |
| `type`           | Event name from the [event catalog](/webhooks/events).                                                            |
| `apiVersion`     | Payload schema identifier, currently the string `"1"`.                                                            |
| `organizationId` | Organization that owns the event. Check that it matches your integration.                                         |
| `merchantId`     | Merchant that owns the resource. May be `null` for older payments with unresolved ownership or a diagnostic test. |
| `createdAt`      | UTC time when the event was captured, rather than its delivery time.                                              |
| `data`           | Immutable resource snapshot at capture time.                                                                      |

Amounts are integer minor units of the field's currency. For example, `10000` with numeric ISO 4217 currency ID `203` means CZK 100.00. Requested and settlement amounts can use different currencies.

Each event type puts its own snapshot inside `data`. See [Event Types](/webhooks/events) for every payload shape and status value.

## Delivery rules [#delivery-rules]

Tapaya sends an event as soon as its change is saved, and keeps sending it until your server answers `2xx`.

| Rule           | Behavior                                                                                               |
| -------------- | ------------------------------------------------------------------------------------------------------ |
| Acknowledgment | Any `2xx` response within 10 seconds. Redirects are not followed.                                      |
| Retries        | Up to 12 attempts over about 20 hours, waiting 1, 2, 4, 8, 16, 32, 64, 128, 256, 360, and 360 minutes. |
| Order          | Not guaranteed. Delivery is at least once, so expect duplicates and older snapshots.                   |
| Concurrency    | 2 requests at a time per organization, shared with manual tests. Other events wait in the queue.       |

A failed delivery never changes the payment itself, and past deliveries cannot be replayed. To catch up after an outage, read the current state through the [payment and merchant APIs](/platform-api/reporting).

## Start integrating [#start-integrating]

<Cards>
  <Card title="Configure a destination" href="/webhooks/configuration">
    Set the URL, choose events, and save your signing secret.
  </Card>

  <Card title="Browse event types" href="/webhooks/events">
    Find the exact trigger for each payment, merchant, and onboarding event.
  </Card>

  <Card title="Verify and test" href="/webhooks/receiving">
    Validate signatures and send a diagnostic webhook.
  </Card>
</Cards>
