> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.coinflow.cash/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.coinflow.cash/_mcp/server.

# Withdraw Webhooks

> **Warning**
>
> **This page is for advanced / cryptocurrency-native companies.** If that's not you, head back to the [Quickstart](/guides/getting-started/quickstart) for the standard flows.

> **Note**
>
> ## Webhooks may be sent more than once—add deduplication logic to prevent duplicate events.

## ✅ Event Types

| Event Type            | Description                                                        |
| :-------------------- | :----------------------------------------------------------------- |
| KYC Created           | KYC process has started                                            |
| KYC Success           | KYC passed                                                         |
| KYC Failure           | KYC failed                                                         |
| Withdraw Pending      | Withdrawal has been initiated                                      |
| Withdraw Success      | Withdrawal submitted to the bank                                   |
| Withdraw Failure      | Withdrawal failed                                                  |
| Withdraw Unclaimed    | PayPal/Venmo payout is awaiting the recipient to claim it          |
| Withdraw On Hold      | PayPal/Venmo payout was placed on hold and cannot be canceled      |
| Payout Account Linked | A new PayPal/Venmo payout destination was created for a withdrawer |
| Interac PIN           | Interac payout received its Interac code                           |

### Sample Webhook Payloads

> **Info**
>
> The `"blockchain": "user"` field in the payloads below is the default value identifying the merchant's own user records — it isn't a network reference.

#### 🧾 KYC Events

**`KYC Created`**

```json KYC Created
{
  "eventType": "KYC Created",
  "category": "KYC",
  "created": "2025-04-08T16:26:32.109Z",
  "data": {
    "wallet": "test-withdrawer-f",
    "blockchain": "user",
    "email": "testwithdrawer-f@gmail.com"
  }
}
```

**`KYC Success`**

```json KYC Success
{
  "eventType": "KYC Success",
  "category": "KYC",
  "created": "2025-04-08T16:26:33.520Z",
  "data": {
    "wallet": "test-withdrawer-f",
    "blockchain": "user",
    "email": "testwithdrawer-f@gmail.com"
  }
}
```

**`KYC Failure`**

```json KYC Failure
{
  "eventType": "KYC Failure",
  "category": "KYC",
  "created": "2025-04-09T20:45:24.515Z",
  "data": {
    "wallet": "test-f",
    "blockchain": "user",
    "email": "test-f@gmail.com "
  }
}
```

#### 💸 Withdraw Events

**`Withdraw Pending`**

```json Withdraw Pending
{
  "eventType": "Withdraw Pending",
  "category": "Withdraw",
  "created": "2025-04-08T17:05:56.718Z",
  "data": {
    "wallet": "user123",
    "blockchain": "user",
    "signature": "5nQq5iVkoEc1gomDENhVNkYVXA61kzjsXKiZiAm6iq36wX3auEdrN1jZBAE5mggZWRbTvfRw5AAiVJ2ah6TaRMXS",
    "userFees": { "cents": 200, "currency": "USD" },
    "userGasFees": { "cents": 0, "currency": "USD" },
    "merchantGasFees": { "cents": 2, "currency": "USD" },
    "total": { "cents": 202, "currency": "USD" },
    "currency": "USD",
    "merchantId": "testtest",
    "idempotencyKey": "merchant-withdrawal-12345"
  }
}
```

**`Withdraw Success`**

```json Withdraw Success
{
  "eventType": "Withdraw Success",
  "category": "Withdraw",
  "created": "2025-04-08T17:06:05.177Z",
  "data": {
    "wallet": "user123",
    "blockchain": "user",
    "signature": "5nQq5iVkoEc1gomDENhVNkYVXA61kzjsXKiZiAm6iq36wX3auEdrN1jZBAE5mggZWRbTvfRw5AAiVJ2ah6TaRMXS",
    "userFees": { "cents": 200, "currency": "USD" },
    "userGasFees": { "cents": 0, "currency": "USD" },
    "merchantGasFees": { "cents": 2, "currency": "USD" },
    "total": { "cents": 202, "currency": "USD" },
    "currency": "USD",
    "merchantId": "testtest",
    "idempotencyKey": "merchant-withdrawal-12345"
  }
}
```

**`Withdraw Failure`**

```json Withdraw Failure
{
  "eventType": "Withdraw Failure",
  "category": "Withdraw",
  "created": "2025-04-08T17:07:05.177Z",
  "data": {
    "wallet": "user123",
    "blockchain": "user",
    "signature": "5nQq5iVkoEc1gomDENhVNkYVXA61kzjsXKiZiAm6iq36wX3auEdrN1jZBAE5mggZWRbTvfRw5AAiVJ2ah6TaRMXS",
    "userFees": { "cents": 200, "currency": "USD" },
    "userGasFees": { "cents": 0, "currency": "USD" },
    "merchantGasFees": { "cents": 2, "currency": "USD" },
    "total": { "cents": 202, "currency": "USD" },
    "currency": "USD",
    "merchantId": "testtest",
    "idempotencyKey": "merchant-withdrawal-12345",
    "reason": "RECEIVER_UNREGISTERED: The recipient does not have a PayPal or Venmo account for this email or phone number"
  }
}
```

> **Info**
>
> For PayPal and Venmo payouts, a `Withdraw Failure` event can include a `reason` field that explains why the payout failed. When PayPal provides an error code, it comes first (for example, `RECEIVER_UNREGISTERED: ...`). The same reason appears as the **Failure Reason** on the withdrawal in the merchant dashboard. If no reason is available, or for other payout methods, `reason` is left out.

**`Withdraw Unclaimed`**

```json Withdraw Unclaimed
{
  "eventType": "Withdraw Unclaimed",
  "category": "Withdraw",
  "created": "2025-04-08T17:08:05.177Z",
  "data": {
    "wallet": "user123",
    "blockchain": "user",
    "signature": "5nQq5iVkoEc1gomDENhVNkYVXA61kzjsXKiZiAm6iq36wX3auEdrN1jZBAE5mggZWRbTvfRw5AAiVJ2ah6TaRMXS",
    "userFees": { "cents": 200, "currency": "USD" },
    "userGasFees": { "cents": 0, "currency": "USD" },
    "merchantGasFees": { "cents": 2, "currency": "USD" },
    "total": { "cents": 202, "currency": "USD" },
    "currency": "USD",
    "merchantId": "testtest",
    "idempotencyKey": "merchant-withdrawal-12345"
  }
}
```

> **Info**
>
> A `Withdraw Unclaimed` event fires when a PayPal or Venmo payout is delivered to a recipient who has not yet accepted the funds (for example, an email or phone number with no PayPal/Venmo account behind it). Coinflow automatically cancels payouts that remain unclaimed after 24 hours, at which point a `Withdraw Failure` event follows.

**`Withdraw On Hold`**

```json Withdraw On Hold
{
  "eventType": "Withdraw On Hold",
  "category": "Withdraw",
  "created": "2025-04-08T17:09:05.177Z",
  "data": {
    "wallet": "user123",
    "blockchain": "user",
    "signature": "5nQq5iVkoEc1gomDENhVNkYVXA61kzjsXKiZiAm6iq36wX3auEdrN1jZBAE5mggZWRbTvfRw5AAiVJ2ah6TaRMXS",
    "userFees": { "cents": 200, "currency": "USD" },
    "userGasFees": { "cents": 0, "currency": "USD" },
    "merchantGasFees": { "cents": 2, "currency": "USD" },
    "total": { "cents": 202, "currency": "USD" },
    "currency": "USD",
    "merchantId": "testtest",
    "idempotencyKey": "merchant-withdrawal-12345"
  }
}
```

> **Info**
>
> A `Withdraw On Hold` event fires once when PayPal places a PayPal or Venmo payout on hold (typically because the recipient's account is limited). PayPal will not let the payout be canceled, so the withdrawal stays pending — for up to \~30 days — until PayPal returns the funds. Use this event to let the recipient know their funds are being held.

#### 🔗 Payout Account Linked Event

A `Payout Account Linked` event fires when a withdrawer creates a **new** PayPal or Venmo payout destination.

The event fires only when a new payout destination token is minted. Re-linking an account that is already on file — including one the withdrawer previously removed — returns the original `token` and does not fire the event.

**`Payout Account Linked`**

```json Payout Account Linked
{
  "eventType": "Payout Account Linked",
  "category": "Withdraw",
  "created": "2025-04-08T17:09:05.177Z",
  "data": {
    "token": "00000000-0000-4000-8000-0000000000aa",
    "userId": "user123",
    "merchantId": "testtest",
    "paymentMethod": "PayPal",
    "payerId": "EXAMPLEPAYER1",
    "email": "recipient@example.com"
  }
}
```

| Field         | Type   | Description                                                                                                                |
| :------------ | :----- | :------------------------------------------------------------------------------------------------------------------------- |
| token         | string | The Coinflow token for the payout destination, matching the token the link endpoints return                                |
| userId        | string | The id of the withdrawer the payout destination belongs to. If you use the `x-coinflow-user-id` header, this is that value |
| merchantId    | string | Your merchant id                                                                                                           |
| paymentMethod | string | `PayPal` or `Venmo`                                                                                                        |
| payerId       | string | Optional. The payer's stable PayPal account id                                                                             |
| email         | string | Optional. The email the account was linked with                                                                            |
| phoneNumber   | string | Optional. The phone number the account was linked with, masked to its last four digits as `(XXX) XXX-1234`                 |
| countryCode   | string | Optional. The dialing country code that accompanies `phoneNumber`                                                          |

> **Warning**
>
> `payerId` is only present for PayPal accounts linked through Log in with PayPal, and only when PayPal returns one. PayPal accounts added manually and all Venmo accounts carry `email` or `phoneNumber` instead. An account is always identified by at least one of `payerId`, `email`, or `phoneNumber` — never assume `payerId` is there.

> **Warning**
>
> `phoneNumber` is masked and is only safe to display, not to match on. Two withdrawers can share the same last four digits, so correlate a payout destination by `token`, which is the same value the link endpoints return.

> **Info**
>
> The `token`, `userId`, `payerId`, and contact values above are **examples only** and are not reflective of real production values.

#### 🔐 Interac PIN Event

This event fires when an Interac payout receives its Interac code (PIN), so you can display the code to the recipient without polling.

| Field        | Type   | Description                                                       |
| :----------- | :----- | :---------------------------------------------------------------- |
| withdrawerId | string | The id of the withdrawer (user or business) the payout belongs to |
| transferId   | string | The provider transfer id for the Interac payout                   |
| pin          | string | The Interac code (PIN) the recipient uses to claim the payout     |

## Advanced: Stablecoin Deposit Webhooks

The events below apply only to merchants accepting stablecoin deposits. If you're integrating standard payouts to bank accounts, you can skip this section.

| Event Type                 | Description                                   |
| :------------------------- | :-------------------------------------------- |
| CryptoDepositFundsReceived | Funds received for stablecoin deposit session |

#### Stablecoin Deposit Events

**`CryptoDepositFundsReceived`**

```json CryptoDepositFundsReceived
{
  "eventType": "CryptoDepositFundsReceived",
  "category": "CryptoDeposit",
  "created": "2024-01-01T00:00:00.000Z",
  "data": {
    "sessionId": "session-123",
    "idempotencyKey": "00000000-0000-0000-0000-000000000000",
    "depositAddress": "deposit-address-here",
    "blockchainChainId": "solana",
    "blockchainName": "Solana",
    "tokenSymbol": "USDC",
    "user": "user-456",
    "amount": {
      "cents": 10000,
      "currency": "USD"
    },
    "merchantId": "merchant-789",
    "transactionHash": "tx-hash-here",
    "receivedAt": "2024-01-01T00:00:00.000Z"
  }
}
```

### Description

This webhook is sent when a stablecoin deposit transaction has been successfully processed and funds have been received. It includes details about the deposit address, settlement network, token details, and the amount received.

The `amount` field contains the received amount in cents with USD currency.

The `idempotencyKey` field is the same value returned by the `crypto-deposit-address` request (searchable on `GET /api/merchant/withdraws`); it falls back to the deposit session id when no caller key was supplied.

### Use Cases

* Confirming successful stablecoin deposits
* Updating user balances
* Triggering downstream processes like withdrawals
* Recording transaction history