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

# Webhook events

> Reference for the webhook event types and envelope OrsunPay sends today.

This page lists the events OrsunPay delivers today. All examples are synthetic. Money values are
decimal strings. See [Webhooks](https://docs.orsunpay.com/webhooks.md) for signature verification and delivery semantics.

## Envelope

Source: `services/brain/src/outbox/merchant-webhook.delivery.ts`.

* `id` (always): Event id, a TypeID `evt_` + 26 characters. Deduplication key, identical on every retry and re-drive.
* `livemode` (always): Boolean. Taken from `data.transaction.livemode`, `true` when that is absent.
* `type` (always): Event type, for example `transaction.updated`.
* `api_version` (always): Payload version, for example `2026-10-31`. Fixed per event by its `created_at`, so retries and re-drives never change it.
* `created_at` (always): ISO 8601 UTC time the event was recorded, stable across retries.
* `created` (some events): Alias of `created_at`, present only on `refund.succeeded` and `refund.failed`.
* `data` (always): Event-specific object.

Event IDs are TypeIDs with the `evt_` prefix. Deduplicate by the signed body's `id`; the
`OrsunPay-Event-Id` header is an unsigned convenience copy.

## Versioning

Every event carries `api_version`. It is fixed per event (by `created_at`), so a retry or a
re-drive sends exactly the same body. New fields and new event types can appear without a new
version; ignore what you do not know. Removing or changing a field always gets a new version,
announced in this changelog first.

| Version | Since | Changes |
| - | - | - |
| `2026-10-31` | first version | First versioned payload: `api_version` added to every event. Event `id` is a TypeID `evt_…` (it was the raw outbox UUID). The same event keeps the same id on every retry and re-drive. `cashier.wallet.effect_requested` documented. |

Before the first version, events were delivered with a UUID `id` and no `api_version`. A
re-drive of such an older event now sends the `evt_` form of the same id and `2026-10-31`.
Wallet receipts and the cabinet journal accept both id forms.

## `transaction.updated`

A sale or payout changed state.

Source: `services/brain/src/transaction/transaction.events.ts`.

`data` contents:

* `transaction`: the serialized transaction; money fields are decimal strings.
* `paymentData`: provider-specific object, `{}` when there is none. May contain additional fields.

```json theme={null}
{
  "id": "evt_0j7s2pft4v8b9t8nj2cra1eg00",
  "livemode": false,
  "type": "transaction.updated",
  "api_version": "2026-10-31",
  "created_at": "2026-10-10T10:00:00.000Z",
  "data": {
    "transaction": {
      "id": "9b2f6c3e-1d4a-4f7b-8e21-5a6c7d8e9f01",
      "livemode": false,
      "orderId": "order_example_001",
      "status": "SUCCESS",
      "amount": "12.30",
      "currency": "EUR"
    },
    "paymentData": {}
  }
}
```

## `test.ping`

A synthetic delivery the merchant triggers to test its receiver. It is not redeliverable and is excluded from endpoint-health failure counts.

Source: `services/brain/src/outbox/outbox.service.ts`.

`data` contents:

* `merchantId`: the merchant UUID the ping was sent for.
* `test`: always `true`.

```json theme={null}
{
  "id": "evt_0j7s2pft4v8b9t8nj2cra1eg02",
  "livemode": true,
  "type": "test.ping",
  "api_version": "2026-10-31",
  "created_at": "2026-10-12T10:00:00.000Z",
  "data": {
    "merchantId": "0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
    "test": true
  }
}
```

## `refund.succeeded`

A refund completed successfully.

Source: `services/brain/src/outbox/refund-webhook.delivery.ts`.
Payload source: `services/brain/src/outbox/refund-webhook.snapshot.ts`.

`data` contents:

* `refund`: `id`, `transactionId`, `amount`, `currency`, `status`, `reason`, `provider`, `providerRefundId`, `errorCode`.
* `transaction`: `id`, `livemode`, `orderId`, `amount`, `refundedAmount`, `refundState` (`none`, `partial` or `full`).

```json theme={null}
{
  "id": "evt_0j7s2pft4v8b9t8nj2cra1eg01",
  "livemode": false,
  "type": "refund.succeeded",
  "api_version": "2026-10-31",
  "created_at": "2026-10-11T10:00:00.000Z",
  "created": "2026-10-11T10:00:00.000Z",
  "data": {
    "refund": {
      "id": "4c1e8a52-7b3d-4e9f-a610-2d3f4a5b6c7d",
      "transactionId": "9b2f6c3e-1d4a-4f7b-8e21-5a6c7d8e9f01",
      "amount": "5.00",
      "currency": "EUR",
      "status": "SUCCEEDED",
      "reason": "requested_by_customer",
      "provider": "example-psp",
      "providerRefundId": "prf_example_001",
      "errorCode": null
    },
    "transaction": {
      "id": "9b2f6c3e-1d4a-4f7b-8e21-5a6c7d8e9f01",
      "livemode": false,
      "orderId": "order_example_001",
      "amount": "12.30",
      "refundedAmount": "5.00",
      "refundState": "partial"
    }
  }
}
```

## `refund.failed`

A refund failed.

Source: `services/brain/src/outbox/refund-webhook.delivery.ts`.
Payload source: `services/brain/src/outbox/refund-webhook.snapshot.ts`.

`data` contents:

* Same shape as `refund.succeeded`; `refund.errorCode` describes the failure.

```json theme={null}
{
  "id": "evt_0j7s2pft4v8b9t8nj2cra1eg03",
  "livemode": false,
  "type": "refund.failed",
  "api_version": "2026-10-31",
  "created_at": "2026-10-11T11:00:00.000Z",
  "created": "2026-10-11T11:00:00.000Z",
  "data": {
    "refund": {
      "id": "4c1e8a52-7b3d-4e9f-a610-2d3f4a5b6c7d",
      "transactionId": "9b2f6c3e-1d4a-4f7b-8e21-5a6c7d8e9f01",
      "amount": "5.00",
      "currency": "EUR",
      "status": "FAILED",
      "reason": "requested_by_customer",
      "provider": "example-psp",
      "providerRefundId": null,
      "errorCode": "PROVIDER_DECLINED"
    },
    "transaction": {
      "id": "9b2f6c3e-1d4a-4f7b-8e21-5a6c7d8e9f01",
      "livemode": false,
      "orderId": "order_example_001",
      "amount": "12.30",
      "refundedAmount": "0.00",
      "refundState": "none"
    }
  }
}
```

## `cashier.wallet.effect_requested`

Cashier only: the operator wallet must apply a credit or capture for a cashier operation. Apply it idempotently by `walletEffect.effectId` and confirm with a wallet receipt that echoes this event `id` (both the `evt_` id and a pre-H4 UUID are accepted).

Source: `services/brain/src/cashier/wallet/effects.repository.ts`.

`data` contents:

* `transaction`: `livemode`, and `id` once the cashier operation has a payment transaction.
* `walletEffect`: `protocol` (1), `effectId` (= `financialKey`), `kind` (`credit`, `capture` or `release`), `operationRevision`, `operation` (scope, player, operation, order and optional transaction ids, `amount`, `currency`, `direction`, `simulation`), optional `reservation` and `settlement`.

```json theme={null}
{
  "id": "evt_0j7s2pft4v8b9t8nj2cra1eg04",
  "livemode": false,
  "type": "cashier.wallet.effect_requested",
  "api_version": "2026-10-31",
  "created_at": "2026-10-12T11:00:00.000Z",
  "data": {
    "transaction": {
      "id": "tr_example",
      "livemode": false
    },
    "walletEffect": {
      "protocol": 1,
      "effectId": "wfe_example_001",
      "financialKey": "wfe_example_001",
      "kind": "credit",
      "operationRevision": "3",
      "operation": {
        "companyId": "co_example",
        "merchantId": "mr_example",
        "livemode": false,
        "playerId": "player_example_001",
        "operatorLoginSessionId": "session_example_001",
        "operationId": "cop_example_001",
        "transactionId": "tr_example",
        "orderId": "cashier:order_example_001",
        "amount": "25.00",
        "currency": "EUR",
        "direction": "deposit",
        "simulation": false
      }
    }
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.