> ## Documentation Index
> Fetch the complete documentation index at: https://requestnetwork-08-25-chore-consolidate-webhook-guidance.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Register signed webhook endpoints, identify who receives each event, and process payloads safely.

## Overview

Webhooks notify your server when Request Network processes a payment, completes KYT screening, or finishes hosted onboarding. Every delivery is an HMAC-signed `POST` request.

A platform owns its Client IDs and Secure Payments. When it links a Client ID to an orchestrator, the orchestrator can create Secure Payments on the platform's behalf. Some events are then delivered to both the platform's Client ID endpoint and the linked orchestrator's endpoint.

You do not subscribe an endpoint to individual event types. An active endpoint receives the events available to the Client ID or orchestrator that registered it.

<Note>
  New platform endpoints are scoped to a Client ID. Existing platform-wide endpoints continue to receive their platform events, but you cannot create new platform-wide endpoints through the current registration flow.
</Note>

## Choose who receives notifications

Register an endpoint for the role that needs the event:

| Recipient            | Authentication                                    | Receives                                                                                           |
| -------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Platform's Client ID | `x-client-id` or the platform's Dashboard session | Events for Secure Payments created with that Client ID.                                            |
| Orchestrator         | `x-orchestrator-key`                              | Hosted-onboarding events and events for Secure Payments it created on behalf of a linked platform. |

Register each role separately, even if both roles use the same callback URL. Each registration has its own signing secret.

<Note>
  **Orchestrator integration:** Registering and managing an orchestrator endpoint requires only `x-orchestrator-key`. Use paired `x-client-id` and `x-orchestrator-key` authentication only when you [create a Secure Payment for a linked platform](/orchestrators/client-id-linking#create-payment-links-for-a-platform).
</Note>

## Register a platform Client ID webhook

Use the platform's Client ID to register an endpoint:

```bash theme={null}
curl -X POST "https://auth.request.network/v1/webhook" \
  -H "Content-Type: application/json" \
  -H "x-client-id: cli_YOUR_CLIENT_ID" \
  -d '{ "url": "https://platform.example.com/webhooks/request-network" }'
```

**Response (201 Created):**

```json theme={null}
{
  "id": "01KJC2WX8EH4MP3DHZB2YQ7N9G",
  "secret": "f3c189a4b5e6d7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2"
}
```

<Warning>
  Save `secret` when you create the endpoint. Request Network returns it only once. Use HTTPS in production; `localhost` is accepted for local development.
</Warning>

If you use a Dashboard session instead of `x-client-id`, include the Client ID in the request body when creating or testing an endpoint. See the [Auth API webhook endpoints](https://auth.request.network/open-api/#tag/webhook) for that session-authenticated form.

### Manage and test platform endpoints

| Method   | Path                     | Purpose                                       |
| -------- | ------------------------ | --------------------------------------------- |
| `GET`    | `/v1/webhook`            | List the Client ID's endpoints.               |
| `PUT`    | `/v1/webhook/:webhookId` | Activate or deactivate an endpoint.           |
| `DELETE` | `/v1/webhook/:webhookId` | Permanently remove an endpoint.               |
| `POST`   | `/v1/webhook/test`       | Send a signed test event to active endpoints. |

Test a platform endpoint with the same Client ID:

```bash theme={null}
curl -X POST "https://auth.request.network/v1/webhook/test" \
  -H "Content-Type: application/json" \
  -H "x-client-id: cli_YOUR_CLIENT_ID" \
  -d '{ "eventType": "payment.confirmed" }'
```

Test deliveries include `x-request-network-test: true`. They use the same signature format and an example payload; they do not represent a real payment or screening decision.

## Register an orchestrator webhook

Use the orchestrator key to register an endpoint:

```bash theme={null}
curl -X POST "https://api.request.network/v2/orchestrators/webhooks" \
  -H "x-orchestrator-key: orc_YOUR_ORCHESTRATOR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://orchestrator.example.com/webhooks/request-network" }'
```

**Response (201 Created):**

```json theme={null}
{
  "webhook": {
    "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
    "url": "https://orchestrator.example.com/webhooks/request-network",
    "isActive": true,
    "createdAt": "2026-08-14T10:00:00.000Z"
  },
  "secret": "4f2c5a8d1b3e6f709c2d4a7b0e1f3c5d8a2b4e6f9c1d3a5b7e0f2c4d6a8b1e3f"
}
```

<Warning>
  Save `secret` when you register the endpoint. Request Network never includes it in list, deactivate, or reactivate responses.
</Warning>

### Manage and test orchestrator endpoints

| Method   | Path                              | Purpose                                                            |
| -------- | --------------------------------- | ------------------------------------------------------------------ |
| `GET`    | `/v2/orchestrators/webhooks`      | List the orchestrator's endpoints, including inactive endpoints.   |
| `DELETE` | `/v2/orchestrators/webhooks/:id`  | Deactivate an endpoint without removing its URL or signing secret. |
| `PATCH`  | `/v2/orchestrators/webhooks/:id`  | Reactivate an endpoint.                                            |
| `POST`   | `/v2/orchestrators/webhooks/test` | Send a signed test event to every active endpoint.                 |

To test an orchestrator endpoint:

```bash theme={null}
curl -X POST "https://api.request.network/v2/orchestrators/webhooks/test" \
  -H "x-orchestrator-key: orc_YOUR_ORCHESTRATOR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "eventType": "client_id.linked" }'
```

Deactivation preserves the endpoint. Registering the same URL again is rejected, including while it is inactive; reactivate it instead. To change the URL, deactivate the old endpoint and register the new one.

## Current webhook events

These are the events for current Secure Payment and orchestrator integrations. The platform's Client ID also receives `payment.confirmed`, KYT, and payer-activity events for Secure Payments created by its linked orchestrator.

| Event                            | Platform's Client ID | Linked orchestrator | Notes                                                                                          |
| -------------------------------- | -------------------- | ------------------- | ---------------------------------------------------------------------------------------------- |
| `client_id.linked`               | No                   | Yes                 | Sent after hosted onboarding completes. Direct API links do not emit this event.               |
| `payment.confirmed`              | Yes                  | Yes                 | Both receive it when the linked orchestrator created the Secure Payment for the platform.      |
| `payment.failed`                 | Yes                  | No                  | Payment execution fails.                                                                       |
| `kyt.screening.completed`        | Yes                  | Yes                 | Sent after a definitive `approved` or `rejected` result. Provider errors do not emit it.       |
| `secure_payment.user_event`      | Yes                  | Yes                 | Best-effort payer activity from the Secure Payment Page. Do not use it as a settlement signal. |
| `secure_payment.access_rejected` | Yes                  | No                  | A wallet outside an incoming payment's payer-wallet allowlist tries to access or pay it.       |

<Note>
  `payment.confirmed` is the settlement signal. `secure_payment.user_event` is browser-reported activity: navigation, network failures, or browser extensions can prevent Request Network from receiving it. Its absence does not prove that the payer did not take that step.
</Note>

## Payload identity and correlation

For a Secure Payment created with a Client ID, payloads identify the platform's Client ID with `clientId`. When the payment was created through an orchestrator, they also include `orchestratorId`.

`orchestratorId` is the orchestrator recorded when the Secure Payment was created. A later link, unlink, or relink does not change past payment events. Use `requestId`, `paymentToken`, or `securePaymentToken` to correlate the event with your own records.

Payment events include an `explorer` URL for [Request Scan](https://scan.request.network) when one is available. `requestId` and `requestID` identify the request, and `paymentReference` is its short unique reference.

### Hosted onboarding completed

`client_id.linked` lets the orchestrator match hosted onboarding to the link intent it created. Use `linkId` or `intentId` to deduplicate repeated deliveries.

```json theme={null}
{
  "event": "client_id.linked",
  "clientId": "cli_PLATFORM_CLIENT_ID",
  "orchestratorId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "linkId": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
  "intentId": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
  "externalId": "merchant_123",
  "destinationId": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e@eip155:8453#B4FD67BB:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
  "destinationWalletAddress": "0x742d35cc6634c0532925a3b844bc454e4438f44e",
  "chain": "base",
  "currency": "USDC",
  "timestamp": "2026-08-14T10:00:00.000Z"
}
```

### Payment confirmed

Do not fulfill an order until you receive `payment.confirmed`.

```json theme={null}
{
  "event": "payment.confirmed",
  "requestId": "0151b394e3c482c5aebaa04eb04508a8db70595470760293f1b258ed96d1fafa93",
  "requestID": "0151b394e3c482c5aebaa04eb04508a8db70595470760293f1b258ed96d1fafa93",
  "paymentReference": "0x2c3366941274c34c",
  "explorer": "https://scan.request.network/request/0151b394e3c482c5aebaa04eb04508a8db70595470760293f1b258ed96d1fafa93",
  "amount": "100.0",
  "totalAmountPaid": "100.0",
  "expectedAmount": "100.0",
  "txHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
  "payerAddress": "0x92Fc3406Fc6BB7A76aC63b2E8b9d02b1B9C3e4d5",
  "payerEoaAddress": "0x7A1F20C4D58E9B0A3C6D4E2F1B8A5C7D9E0F1234",
  "network": "ethereum",
  "currency": "USDC",
  "paymentCurrency": "USDC",
  "fees": [],
  "clientId": "cli_PLATFORM_CLIENT_ID",
  "orchestratorId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "timestamp": "2026-08-14T10:00:00.000Z"
}
```

`payerAddress` is the address used to make the payment. `payerEoaAddress` is the payer's connected wallet and can differ when a smart account is used. Either can be `null` when unavailable.

### Payment failed

```json theme={null}
{
  "event": "payment.failed",
  "requestId": "0151b394e3c482c5aebaa04eb04508a8db70595470760293f1b258ed96d1fafa93",
  "requestID": "0151b394e3c482c5aebaa04eb04508a8db70595470760293f1b258ed96d1fafa93",
  "paymentReference": "0x2c3366941274c34c",
  "subStatus": "insufficient_funds",
  "paymentProcessor": "request-network"
}
```

### KYT screening completed

KYT results are sent only for definitive `approved` and `rejected` outcomes. If an orchestrator-controlled plan has a backup provider, Request Network tries it after a technical provider failure before deciding whether screening completed.

```json theme={null}
{
  "event": "kyt.screening.completed",
  "paymentToken": "01KYM5CZ51K0N1KJ4F8S73BE3N",
  "walletAddress": "0x2e2e5c79f571ef1658d4c2d3684a1fe97dd30570",
  "eoaAddress": "0x2e2e5c79f571ef1658d4c2d3684a1fe97dd30570",
  "smartAccountAddress": null,
  "status": "approved",
  "provider": "hypernative",
  "policyId": "11111111-1111-4111-8111-111111111111",
  "clientId": "cli_PLATFORM_CLIENT_ID",
  "orchestratorId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "timestamp": "2026-08-14T10:00:00.000Z"
}
```

### Secure Payment user event

`secure_payment.user_event` reports `wallet_connected`, `payment_sent_to_wallet`, or `payment_approved_in_wallet`. `occurredAt` and `properties` come from the payer's browser; `timestamp` is added by Request Network when it receives the event.

| `userEvent`                  | Meaning                                                                                          |
| ---------------------------- | ------------------------------------------------------------------------------------------------ |
| `wallet_connected`           | The payer connected a wallet on the Secure Payment Page.                                         |
| `payment_sent_to_wallet`     | The payment transaction was handed to the payer's wallet for signature.                          |
| `payment_approved_in_wallet` | The payer approved the payment in its wallet. This is not confirmation that it settled on-chain. |

```json theme={null}
{
  "event": "secure_payment.user_event",
  "userEvent": "payment_approved_in_wallet",
  "securePaymentToken": "spt_3fk29ax7...",
  "requestId": "01JD3E6JD46KY4KKV7X9V0MZ7W",
  "requestIds": ["01JD3E6JD46KY4KKV7X9V0MZ7W"],
  "clientId": "cli_PLATFORM_CLIENT_ID",
  "orchestratorId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "occurredAt": "2026-08-05T14:03:21.512Z",
  "timestamp": "2026-08-05T14:03:22.104Z",
  "properties": {
    "wallet_provider": "metamask",
    "payment_submission_id": "0x6a4f...e21b",
    "payment_submission_id_type": "evm_tx_hash",
    "selected_source_chain": "base",
    "payment_type": "single"
  }
}
```

### Payer-wallet access rejected

`secure_payment.access_rejected` is emitted when a wallet that is not on an incoming payment's `allowedPayerAddresses` allowlist tries to access or pay it. It is not a KYT result. Repeated attempts by the same wallet on the same payment are normally suppressed for 10 minutes.

```json theme={null}
{
  "event": "secure_payment.access_rejected",
  "requestId": "0151b394e3c482c5aebaa04eb04508a8db70595470760293f1b258ed96d1fafa93",
  "attemptedPayerWalletAddress": "0x2e2e5c79f571ef1658d4c2d3684a1fe97dd30570",
  "clientId": "cli_PLATFORM_CLIENT_ID",
  "orchestratorId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "timestamp": "2026-08-10T10:05:00.000Z"
}
```

See [Restrict payer wallets](/use-cases/restrict-payer-wallets) to configure the allowlist.

| Field                         | Description                                                                                         |
| ----------------------------- | --------------------------------------------------------------------------------------------------- |
| `requestId`                   | The request the wallet tried to access.                                                             |
| `attemptedPayerWalletAddress` | The rejected wallet address. EVM addresses are lowercased; TRON addresses keep their original case. |
| `timestamp`                   | When Request Network emitted the event.                                                             |

## Delivery requirements

Verify `x-request-network-signature` against the raw request body before you parse it. Use `x-request-network-delivery` as your durable idempotency key: Request Network retries failed deliveries, so the same event can arrive more than once.

* Use HTTPS for production endpoints.
* Store each endpoint's signing secret securely; it is returned only when that endpoint is created.
* Handle unknown event names safely so a new event does not fail your endpoint.

For an Express handler, local testing with ngrok, and reconciliation patterns, see [Webhook reconciliation](/use-cases/webhook-reconciliation).

### Delivery headers

| Header                          | Description                                        |
| ------------------------------- | -------------------------------------------------- |
| `x-request-network-signature`   | HMAC-SHA256 of the raw JSON body, encoded as hex.  |
| `x-request-network-delivery`    | Stable delivery ID. Use it as the idempotency key. |
| `x-request-network-retry-count` | Current attempt: `0` to `3`.                       |
| `x-request-network-test`        | `true` for test deliveries only.                   |
| `content-type`                  | `application/json`.                                |

### Retry policy

Request Network retries non-2xx responses, timeouts, and connection errors. A delivery has four attempts in total: the initial request plus retries after 1, 5, and 15 seconds. Each attempt has a five-second timeout.

Return a 2xx response only after you have safely recorded the delivery. If processing fails, return a non-2xx response so Request Network retries it.

## Troubleshooting

**Signature verification fails**

* Verify the signature against the raw request body, not a parsed or re-serialized body.
* Confirm that you saved the secret returned when this specific endpoint was created.
* Confirm that the endpoint's platform or orchestrator registration is active.

**No webhook arrives**

* Confirm that the relevant Client ID or orchestrator has an active endpoint.
* Confirm that the event belongs to that recipient in [Current webhook events](#current-webhook-events).
* Send a test event to verify endpoint reachability and signature handling.

## Legacy integrations

These events remain available for existing API integrations. They do not apply to current Dashboard, Secure Payment Page, or orchestrator workflows.

| Event                    | Legacy flow                        |
| ------------------------ | ---------------------------------- |
| `payment.partial`        | Partial-payment flow               |
| `payment.refunded`       | Existing refund flows              |
| `payment.processing`     | Crypto-to-fiat processing          |
| `compliance.updated`     | Crypto-to-fiat compliance updates  |
| `payment_detail.updated` | Crypto-to-fiat bank-detail updates |
| `request.recurring`      | Recurring requests                 |

## Related webhook pages

<CardGroup cols={2}>
  <Card title="Webhooks & Events" href="/api-features/webhooks-events" icon="bell">
    Learn the event categories and common webhook use cases.
  </Card>

  <Card title="Webhook reconciliation" href="/use-cases/webhook-reconciliation" icon="code">
    Implement a signed webhook handler and process events safely.
  </Card>
</CardGroup>

## Related

<CardGroup cols={3}>
  <Card title="Client ID linking" href="/orchestrators/client-id-linking" icon="link">
    Link a platform's Client ID and receive hosted-onboarding results.
  </Card>

  <Card title="Orchestrator KYT plans" href="/orchestrators/kyt-plans" icon="shield-halved">
    Configure transaction screening for linked platforms.
  </Card>

  <Card title="Restrict payer wallets" href="/use-cases/restrict-payer-wallets" icon="shield">
    Allow only selected payer wallets for an incoming payment.
  </Card>
</CardGroup>
