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

# Webhooks

> Get real-time notifications for deposits, transfers, customers, and verification.

Webhooks push real-time events to your server so you don't have to poll. Use them to react to
deposits, transfers, customer creation, and verification state changes.

## Add an endpoint

<Steps>
  <Step title="Open Webhooks">
    In the [dashboard](https://dashboard.yara.cash), go to **Webhooks** and click **Add endpoint**.
  </Step>

  <Step title="Set your URL">
    Enter an HTTPS URL on your server that can receive `POST` requests.
  </Step>

  <Step title="Choose events">
    Subscribe to the events you care about. You can change these any time.
  </Step>
</Steps>

## Wallet events

| Event                      | Fires when                                                                          |
| -------------------------- | ----------------------------------------------------------------------------------- |
| `deposit.confirmed`        | A deposit is confirmed and credited to your balance.                                |
| `transfer.submitted`       | The payout provider accepts a transfer for processing.                              |
| `transfer.succeeded`       | A transfer settles successfully.                                                    |
| `transfer.failed`          | A transfer fails terminally and Yara releases the reserved debit.                   |
| `transfer.requires_review` | A transfer has an ambiguous or inconsistent outcome and its debit remains reserved. |

Transfer lifecycle payloads contain `transfer_id`, your `reference`, and the normalized `status`.
Treat `REQUIRES_REVIEW` as non-terminal. Yara may later reconcile the transfer to `SUCCEEDED` or
`FAILED`.

## Customer events

| Event                                         | Fires when                                                 |
| --------------------------------------------- | ---------------------------------------------------------- |
| `customer.created`                            | A customer is ready for verification.                      |
| `customer.verification.submitted`             | Yara accepts a customer verification submission.           |
| `customer.verification.approved`              | A customer verification submission becomes verified.       |
| `customer.verification.information_requested` | A customer verification submission needs more information. |
| `customer.verification.rejected`              | A customer verification submission is rejected.            |

See [Customer webhooks](/virtual-accounts/webhooks) for payload fields and verification-state
behavior.

## USD virtual-account deposit events

| Event                               | Fires when                                                                                                |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `virtual_account.deposit.received`  | Yara stores a provider-confirmed USD deposit with customer attribution. No balance credit is implied yet. |
| `virtual_account.deposit.completed` | Yara credits your general USD merchant balance after deducting the snapshotted Yara fee.                  |
| `virtual_account.deposit.reversed`  | Yara posts a compensating debit for a previously completed deposit.                                       |

These events include the Yara virtual-account, customer, and deposit IDs; gross amount; Yara fee;
net merchant credit; normalized status; and timestamps. They do not expose provider fees or
provider balance movements. Treat the completed event as the balance-credit notification.

## Transfer funding events

| Event                       | Fires when                                                                                                                                  |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `transfer.funding.received` | A bank or crypto payment is provider-verified and stored as a transfer-funding receipt.                                                     |
| `transfer.funding.flagged`  | A bank or crypto payment needs review because its amount is mismatched or the funding intent was already credited by another exact payment. |

Both events contain `transfer_id`, `funding_intent_id`, and a merchant-safe `receipt` snapshot.
`transfer.funding.received` does not mean the payout has already been submitted. A mismatched bank
or crypto receipt is followed by `transfer.funding.flagged` and receives no automatic ledger
credit or reservation.

```json theme={null}
{
  "id": "4a064a83-5e91-5f9f-a17e-e30abb3f20bd",
  "event": "transfer.funding.flagged",
  "data": {
    "transfer_id": "76179a66-8695-47fd-bca4-310eaa816077",
    "funding_intent_id": "0f92c60a-6870-48ba-b589-a5f9c91ac5ec",
    "receipt": {
      "id": "c81427de-2ca1-4d4b-af89-5bdb65764d8c",
      "status": "REQUIRES_REVIEW",
      "method": "BANK_TRANSFER",
      "provider_transaction_id": "palmpay-order-1",
      "received_amount": { "value": "160000", "currency": "NGN" },
      "expected_amount": { "value": "160640", "currency": "NGN" },
      "variance_amount": { "value": "-640", "currency": "NGN" },
      "gross_usd": { "value": "100", "currency": "USD" },
      "fee_usd": { "value": "0.398406", "currency": "USD" },
      "net_usd": { "value": "99.601594", "currency": "USD" },
      "flag": {
        "code": "AMOUNT_MISMATCH",
        "message": "Funding amount does not match the expected amount"
      },
      "received_at": "2026-06-16T03:02:00Z"
    }
  },
  "created_at": "2026-06-16T03:02:01Z"
}
```

## Payload

Every webhook is a JSON `POST` with an event ID, event name, resource data, and creation time.

```json theme={null}
{
  "id": "d723cab9-1ad4-4d4d-821f-6704d834d575",
  "event": "deposit.confirmed",
  "data": {
    "deposit_id": "741eec3c-5596-45b6-a88d-3627a236192f",
    "asset": "USDC",
    "chain": "BASE",
    "amount_usd": "100.000000",
    "status": "CONFIRMED",
    "tx_hash": "0x4f5d2d7a2c8a95c3"
  },
  "created_at": "2026-06-16T03:00:00Z"
}
```

## Verify signatures

Each endpoint has a signing secret. Yara signs the exact request body with HMAC-SHA256 and sends the
lowercase hexadecimal digest in `X-Yara-Signature`.

Calculate the digest from the raw body before JSON parsing. Compare it to the header using a
constant-time comparison. Reject the delivery when the values do not match. Rotate the secret from
the dashboard if you suspect it has been exposed.

## Inspect delivery history

You can review outbound event history from the API:

```bash theme={null}
curl "https://api.yara.cash/v1/webhook-events?limit=50" \
  --header "x-yara-api-key: $YARA_API_KEY"
```

```json theme={null}
{
  "data": [
    {
      "id": "d723cab9-1ad4-4d4d-821f-6704d834d575",
      "event_type": "deposit.confirmed",
      "resource_type": "deposit",
      "resource_id": "741eec3c-5596-45b6-a88d-3627a236192f",
      "payload": {
        "deposit_id": "741eec3c-5596-45b6-a88d-3627a236192f",
        "status": "CONFIRMED"
      },
      "status": "DISPATCHED",
      "created_at": "2026-06-16T03:00:00Z"
    }
  ],
  "meta": { "page": 1, "limit": 50, "total": 1, "total_pages": 1 }
}
```

## Best practices

* **Respond fast.** Return a `2xx` quickly and do heavy work asynchronously.
* **Be idempotent.** The same event may be delivered more than once — de-duplicate on the event `id`.
* **Retry-friendly.** Failed deliveries are retried; you can review status in the dashboard or via the endpoint above.
