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

# Webhook Events

> High-level event inventory and webhook payload envelope

## Overview

Daya sends merchant webhooks for funding account, deposit, transfer, withdrawal, and customer verification lifecycle changes.

Every webhook uses the same envelope:

```json theme={null}
{
  "event": "transfer.completed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "650e8400-e29b-41d4-a716-446655440000",
    "status": "SETTLED",
    "rail": "NGN_BANK"
  },
  "timestamp": "2026-03-10T09:03:00Z"
}
```

`event` tells you what changed, `id` identifies the webhook event for idempotency, and `data` is the public API response shape for the resource that changed.

## Common Payload Fields

<ParamField body="event" type="string">
  Event type for the lifecycle transition that occurred.
</ParamField>

<ParamField body="id" type="string">
  Unique webhook event identifier. Use this value for idempotency.
</ParamField>

<ParamField body="data" type="object">
  Resource payload for the event. The shape follows the resource response linked below.
</ParamField>

<ParamField body="timestamp" type="string">
  RFC3339 timestamp for when the event was emitted.
</ParamField>

## Data Shapes

Webhook events are documented here at the event-name level. The `data` object follows the same public response object returned by the corresponding resource endpoint.

| Event family              | `data` shape                                                | Resource docs                                                              |
| ------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------- |
| `funding_account.*`       | Funding account response object                             | [Get Funding Account](/api-reference/funding-accounts/get-funding-account) |
| `deposit.*`               | Deposit response object                                     | [Get Deposit](/api-reference/deposits/get-deposit)                         |
| `transfer.*`              | Transfer response object                                    | [Get Transfer](/api-reference/transfers/get-transfer)                      |
| `withdrawal.*`            | Withdrawal response object                                  | [Get Withdrawal](/api-reference/merchant-balance/get-withdrawal)           |
| `customer.verification.*` | Customer response object with the latest verification state | [Get Customer](/api-reference/customers/get-customer)                      |

<Tip>
  If you need the latest state while processing a webhook, fetch the resource again by the ID in `data`.
</Tip>

## Deposit Events

| Event                     | Terminal? | When Sent                                                           |
| ------------------------- | --------- | ------------------------------------------------------------------- |
| `deposit.received`        | No        | Deposit received (NGN or crypto)                                    |
| `deposit.processing`      | No        | Settlement has started and may be waiting on conversion or delivery |
| `deposit.requires_review` | No        | Deposit needs review before it can continue                         |
| `deposit.completed`       | Yes       | Deposit reached its settlement destination                          |
| `deposit.failed`          | Yes       | Deposit permanently fails                                           |
| `deposit.reversed`        | Yes       | A completed deposit was reversed                                    |

Deposit payloads for NGN and crypto receive flows include `funding_account_id`. When a developer fee is configured, deposit payloads include `developer_fee` and `customer_amount`. The developer fee is deducted before the final customer amount is calculated; it is not added as a separate charge. Track the merchant-facing settlement lifecycle with `deposit.*` events.

## Funding Account Events

Funding account events track receive-instruction provisioning and disablement. The `data` object is the public funding account response.

| Event                      | Terminal? | When Sent                                                   |
| -------------------------- | --------- | ----------------------------------------------------------- |
| `funding_account.created`  | No        | Funding account record has been created in `PENDING` status |
| `funding_account.active`   | No        | Payment details are ready and the account is active         |
| `funding_account.failed`   | Yes       | Receive instruction provisioning failed                     |
| `funding_account.disabled` | Yes       | Active funding account was disabled                         |

## Transfer Events

Transfer events are emitted for `POST /v1/transfers` and follow the merchant-created transfer lifecycle.

| Event                      | Terminal? | When Sent                                                          |
| -------------------------- | --------- | ------------------------------------------------------------------ |
| `transfer.created`         | No        | Transfer record and initial attempt have been created              |
| `transfer.processing`      | No        | Funds have been locked and provider submission has been queued     |
| `transfer.requires_review` | No        | Risk or ops policy flagged the transfer for review                 |
| `transfer.submitted`       | No        | Provider accepted the transfer submission                          |
| `transfer.completed`       | Yes       | Provider success and ledger finalization are complete              |
| `transfer.failed`          | Yes       | Transfer failed terminally after release or failure reconciliation |
| `transfer.reversed`        | Yes       | A previously completed transfer was reversed                       |

## Withdrawal Events

| Event                  | Terminal? | When Sent                            |
| ---------------------- | --------- | ------------------------------------ |
| `withdrawal.created`   | No        | Withdrawal request has been accepted |
| `withdrawal.submitted` | No        | Withdrawal submitted to chain        |
| `withdrawal.completed` | Yes       | Withdrawal confirmed on-chain        |
| `withdrawal.failed`    | Yes       | Withdrawal failed                    |

## Customer Verification Events

| Event                             | Terminal? | When Sent                                           |
| --------------------------------- | --------- | --------------------------------------------------- |
| `customer.verification.submitted` | No        | Customer verification has been submitted for review |
| `customer.verification.approved`  | Yes       | Customer verification has been approved             |
| `customer.verification.rejected`  | Yes       | Customer verification has been rejected             |

<Info>
  `funding_account.*` and `customer.verification.*` events use the same webhook envelope as money movement events. Funding account payloads use the public funding account response shape.
</Info>

## Lifecycle Examples

These examples show how webhook names follow the public resource being reconciled.

### Funding Account Deposit

When a customer sends NGN to a funding account's virtual account, the incoming money is a deposit. The payment detail is the funding account; the money movement is tracked with `deposit.*` events.

| Step                   | Event                                         | Notes                                                     |
| ---------------------- | --------------------------------------------- | --------------------------------------------------------- |
| Funds arrive           | `deposit.received`                            | Daya records the NGN deposit.                             |
| Settlement starts      | `deposit.processing`                          | Sent when delivery or conversion work begins.             |
| Deposit completes      | `deposit.completed`                           | Funds have reached the configured settlement destination. |
| Review or failure path | `deposit.requires_review` or `deposit.failed` | Sent if the deposit cannot proceed automatically.         |

### Internal Balance to NGN Bank Transfer

When a merchant sends withdrawal balance to an NGN bank account through `POST /v1/transfers`, the public resource is a transfer.

| Step                        | Event                      | Notes                                                               |
| --------------------------- | -------------------------- | ------------------------------------------------------------------- |
| Request accepted            | `transfer.created`         | Transfer record and initial attempt exist.                          |
| Funds locked                | `transfer.processing`      | Funds are held and provider submission is queued.                   |
| Manual review, if needed    | `transfer.requires_review` | Risk or ops policy paused the transfer.                             |
| Provider accepts submission | `transfer.submitted`       | Provider accepted the transfer request.                             |
| Final success               | `transfer.completed`       | Provider success and ledger finalization are complete.              |
| Final failure               | `transfer.failed`          | Transfer failed terminally after release or failure reconciliation. |

### Crypto Wallet Withdrawal

When a merchant sends stablecoin or crypto from the withdrawal balance to an on-chain wallet, the public resource is a withdrawal.

| Step                           | Event                  | Notes                                                |
| ------------------------------ | ---------------------- | ---------------------------------------------------- |
| Request accepted               | `withdrawal.created`   | Withdrawal record exists.                            |
| On-chain transaction submitted | `withdrawal.submitted` | Daya submitted the withdrawal to the chain/provider. |
| On-chain transaction confirmed | `withdrawal.completed` | Withdrawal is confirmed and complete.                |
| Final failure                  | `withdrawal.failed`    | Withdrawal failed terminally.                        |

## Payload Examples

These examples are intentionally representative. The full `data` object follows the linked resource response shape for each event family.

### Funding Account Active

```json theme={null}
{
  "event": "funding_account.active",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "object": "funding_account",
    "id": "750e8400-e29b-41d4-a716-446655440000",
    "type": "PERMANENT",
    "status": "ACTIVE",
    "rail": "NGN_VIRTUAL_ACCOUNT",
    "customer_id": "650e8400-e29b-41d4-a716-446655440000",
    "currency": "NGN",
    "developer_fee": {
      "percentage": "2.5"
    },
    "settlement_destination": {
      "type": "INTERNAL_BALANCE"
    },
    "instructions": [
      {
        "type": "NGN_VIRTUAL_ACCOUNT",
        "status": "ACTIVE",
        "bank_name": "Wema Bank",
        "bank_code": "035",
        "account_number": "1234567890",
        "account_name": "Daya - Ada Lovelace",
        "currency": "NGN"
      }
    ],
    "created_at": "2026-01-05T15:04:05Z",
    "updated_at": "2026-01-05T15:04:10Z"
  },
  "timestamp": "2026-01-05T15:04:10Z"
}
```

### Deposit Completed

```json theme={null}
{
  "event": "deposit.completed",
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "data": {
    "type": "CRYPTO_DEPOSIT",
    "id": "850e8400-e29b-41d4-a716-446655440000",
    "funding_account_id": "750e8400-e29b-41d4-a716-446655440000",
    "customer_id": "650e8400-e29b-41d4-a716-446655440000",
    "amount": "12.50",
    "currency": "USDC",
    "status": "COMPLETED",
    "settlement_status": "COMPLETED",
    "settlement_mode": "NGN_PAYOUT",
    "asset": "USDC",
    "chain": "BASE",
    "fees": {
      "total_fee_usd": "0.0500"
    },
    "developer_fee": {
      "percentage": "10",
      "amount": "1.25",
      "currency": "USD"
    },
    "customer_amount": {
      "amount": "16800.00",
      "currency": "NGN"
    },
    "created_at": "2026-01-05T15:04:05Z",
    "updated_at": "2026-01-05T15:04:10Z"
  },
  "timestamp": "2026-01-05T15:04:10Z"
}
```

### Transfer Completed

```json theme={null}
{
  "event": "transfer.completed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "id": "850e8400-e29b-41d4-a716-446655440000",
    "reference": "txn_ngn_001",
    "status": "SETTLED",
    "rail": "NGN_BANK",
    "currency": "NGN",
    "amount": "50000.000000",
    "debit_currency": "USD",
    "debit_amount": "33.070000",
    "fee": "0.810000",
    "rate": {
      "side": "SELL",
      "value": "1550.00",
      "captured_at": "2026-01-05T15:04:05Z"
    },
    "on_behalf_of": null,
    "created_at": "2026-01-05T15:04:05Z",
    "settled_at": "2026-01-05T15:10:00Z"
  },
  "timestamp": "2026-01-05T15:10:00Z"
}
```

### Customer Verification Approved

```json theme={null}
{
  "event": "customer.verification.approved",
  "id": "450e8400-e29b-41d4-a716-446655440004",
  "data": {
    "id": "650e8400-e29b-41d4-a716-446655440000",
    "email": "customer@example.com",
    "first_name": "John",
    "last_name": "Doe",
    "tier_1_kyc_complete": true,
    "tier_2_kyc_complete": true,
    "is_verified": true,
    "capabilities": [
      {
        "name": "base",
        "status": "approved"
      },
      {
        "name": "usd_banking",
        "status": "approved"
      }
    ],
    "rejection_reasons": [],
    "created_at": "2026-01-05T15:04:05Z",
    "updated_at": "2026-01-05T16:00:00Z"
  },
  "timestamp": "2026-01-05T16:00:00Z"
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhook Overview" icon="bell" href="/api-reference/webhooks/overview">
    Delivery guarantees, retries, and handler guidance
  </Card>

  <Card title="Webhook Verification" icon="shield-check" href="/api-reference/webhooks/verification">
    Verify the HMAC signature on incoming requests
  </Card>
</CardGroup>
