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

# Transaction events

> Example payloads for every transaction webhook, including step-required and refund events.

Transaction events fire when a transaction is created and whenever its status changes.

## `transaction_created`

Sent as soon as the transaction record exists, before any money has moved.

```json theme={null}
{
  "event": "transaction_created",
  "data": {
    "transactionId": "BeOfXV1NVIcZlsSVeQAF",
    "status": "pending",
    "type": "withdrew",
    "externalReference": "unique-ref"
  },
  "timestamp": "2024-10-03T16:33:14.600Z"
}
```

## `transaction_updated`

Sent on every status change, and whenever the transaction needs the customer to do something.

```json Full shape theme={null}
{
  "event": "transaction_updated",
  "data": {
    "transactionId": "string",
    "status": "string",
    "type": "string",
    "externalReference": "string",
    "stepRequired": "string",
    "redirectUrl": "https://test-redirect.com",
    "method": "string",
    "thirdPartyReference": "string",
    "note": "string",
    "originalTransactionId": "string"
  },
  "timestamp": "ISO-8601 timestamp"
}
```

| Field                   | Notes                                                           |
| :---------------------- | :-------------------------------------------------------------- |
| `stepRequired`          | Optional. e.g. `otp`, `redirect`, `pin`, `address_verification` |
| `redirectUrl`           | Provided when `stepRequired` is `redirect`                      |
| `method`                | Optional. e.g. `momo`, `bank`, `card`, `opay`                   |
| `thirdPartyReference`   | Optional. e.g. an M-Pesa reference                              |
| `note`                  | Optional. Often carries the error or provider message           |
| `originalTransactionId` | Returned on refund transaction updates only                     |

### Terminal outcomes

<CodeGroup>
  ```json Successful theme={null}
  {
    "event": "transaction_updated",
    "data": {
      "transactionId": "BeOfXV1NVIcZlsSVeQAF",
      "status": "successful",
      "type": "deposit",
      "externalReference": "order_12345",
      "method": "momo",
      "thirdPartyReference": "TEQTEYRU"
    },
    "timestamp": "2024-10-03T16:34:02.100Z"
  }
  ```

  ```json Failed theme={null}
  {
    "event": "transaction_updated",
    "data": {
      "transactionId": "BeOfXV1NVIcZlsSVeQAF",
      "status": "failed",
      "type": "deposit",
      "externalReference": "order_12345",
      "method": "momo",
      "note": "User could not be reached by stk"
    },
    "timestamp": "2024-10-03T16:34:02.100Z"
  }
  ```
</CodeGroup>

### Step required

These arrive with `status: "pending"` — the transaction is paused waiting on the customer, not
failed.

<CodeGroup>
  ```json Redirect required theme={null}
  {
    "event": "transaction_updated",
    "data": {
      "transactionId": "test123",
      "status": "pending",
      "type": "deposit",
      "externalReference": "mnvmcvcmvlc",
      "stepRequired": "redirect",
      "redirectUrl": "https://test-redirect.com",
      "method": "momo"
    },
    "timestamp": "ISO-8601 timestamp"
  }
  ```

  ```json OTP required theme={null}
  {
    "event": "transaction_updated",
    "data": {
      "transactionId": "test123",
      "status": "pending",
      "type": "deposit",
      "externalReference": "mnvmcvcmvlc",
      "stepRequired": "otp",
      "method": "momo"
    },
    "timestamp": "ISO-8601 timestamp"
  }
  ```

  ```json PIN required (card) theme={null}
  {
    "event": "transaction_updated",
    "data": {
      "transactionId": "luQybnMnvjgnWEF6ZFyJ",
      "status": "pending",
      "type": "deposit",
      "externalReference": "1234567890",
      "stepRequired": "pin",
      "method": "card"
    },
    "timestamp": "2026-03-05T19:39:30.624Z"
  }
  ```
</CodeGroup>

How to act on each value is covered in
[charges overview](/guides/collections/overview#mid-charge-steps).

## Refund updates

Refunds use the standard `transaction_updated` event with `type: "refund"`. Here `transactionId`
is the **refund** transaction, and `originalTransactionId` is the deposit being reversed.

```json Refund successful theme={null}
{
  "event": "transaction_updated",
  "data": {
    "transactionId": "unique-refund-transaction-id",
    "originalTransactionId": "lBK9bMny2gs4hLsG3XGq",
    "status": "successful",
    "type": "refund",
    "externalReference": "refund_order_12345",
    "amount": 25,
    "currency": "KES",
    "method": "momo"
  },
  "timestamp": "ISO-8601 timestamp"
}
```

<Note>
  Match refunds back to the original order through `originalTransactionId`, not
  `transactionId` — the latter is a new transaction in its own right.
</Note>

## Status values

| Status       | Meaning                                 |
| :----------- | :-------------------------------------- |
| `pending`    | The transaction is being processed.     |
| `successful` | The transaction completed successfully. |
| `failed`     | The transaction failed.                 |

<Warning>
  Only `successful` means funds moved. A `pending` event carrying a `stepRequired` value is a
  request for customer action, not an outcome — keep waiting for a terminal status.
</Warning>

## Testing your handler

Use [Simulate Webhook](/api-reference/endpoint/simulate-webhook) in the sandbox to fire any of
these shapes at your endpoint on demand, without needing to drive a real transaction into the
matching state.
