Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 93 additions & 150 deletions api-reference/webhooks.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: "Webhooks"
description: "Complete webhook implementation guide with event types, security, and retry configuration"
description: "Configure platform Client ID and orchestrator webhooks, including event delivery, signatures, and retries."
---

## Overview

Webhooks deliver real-time notifications when payment and request events occur. Configure your endpoints to receive HMAC-signed POST requests with automatic retry logic and comprehensive event data.
Webhooks deliver HMAC-signed notifications for platform Client ID and orchestrator flows. Each endpoint is configured separately and can receive automatic retries.

## Webhook Configuration
## Platform Client ID webhooks

Manage webhooks in the [Dashboard](https://dashboard.request.network) or programmatically through the Auth API at `auth.request.network`. Each webhook is scoped to the Client ID that creates it; events for any payment link or request created with that Client ID are delivered to that webhook.

Expand Down Expand Up @@ -52,6 +52,89 @@
# Use the HTTPS URL (e.g., https://abc123.ngrok.io/webhook) as the webhook URL
```

## Orchestrator webhooks

Orchestrator webhooks are owned by your orchestrator. Register and manage them with `x-orchestrator-key`, not a platform's `x-client-id`.

Register an endpoint before you send a hosted onboarding URL to a platform. Its active endpoints receive:

- [`client_id.linked`](#client-id-linked) after the platform completes hosted onboarding.
- [`kyt.screening.completed`](#kyt-screening-completed) after an orchestrator-linked payment reaches a definitive screening result.

### Register an endpoint

```bash
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://partner.example.com/webhooks/request-network" }'
```

The response includes the endpoint and a signing secret:

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

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

Verify the `x-request-network-signature` HMAC-SHA256 header against the raw request body before you process an event. See [Signature Verification](#signature-verification). Webhook deliveries may be retried, so your endpoint must safely handle the same notification more than once.

### Test your endpoint

Send a signed mock event to every active endpoint:

```bash
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" }'
```

```json
{
"sent": 1,
"failed": 0
}
```

Test deliveries include `x-request-network-test: true`. They use the same signing process and payload shape as a real event, with placeholder values.

### Manage endpoints

List every endpoint registered to your orchestrator, including inactive ones:

```bash
curl "https://api.request.network/v2/orchestrators/webhooks" \
-H "x-orchestrator-key: orc_YOUR_ORCHESTRATOR_KEY"
```

To stop delivery without removing the endpoint, deactivate it:

```bash
curl -X DELETE "https://api.request.network/v2/orchestrators/webhooks/01ARZ3NDEKTSV4RRFFQ69G5FAV" \
-H "x-orchestrator-key: orc_YOUR_ORCHESTRATOR_KEY"
```

To resume delivery, reactivate the same endpoint:

```bash
curl -X PATCH "https://api.request.network/v2/orchestrators/webhooks/01ARZ3NDEKTSV4RRFFQ69G5FAV" \
-H "x-orchestrator-key: orc_YOUR_ORCHESTRATOR_KEY"
```

Deactivation preserves the endpoint URL and signing secret. Registering the same URL again is rejected, even while it is inactive; reactivate it instead. To use a different URL, deactivate the old endpoint and register the new one.

## Event Types

<Info>
Expand All @@ -62,7 +145,7 @@

| Event | Description | Context | Primary Use |
|-------|-------------|---------|-------------|
| `payment.confirmed` | Payment fully completed and settled | After blockchain confirmation | Complete fulfillment, release goods |

Check warning on line 148 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L148

Did you really mean 'blockchain'?
| `payment.partial` | Partial payment received for request | Installments, partial orders | Update balance, allow additional payments |
| `payment.failed` | Payment execution failed | Recurring payments, cross-chain transfers | Notify failure, retry logic, pause subscriptions |
| `payment.refunded` | Payment has been refunded to payer | Cross-chain payment failures, refund scenarios | Update order status, notify customer |
Expand All @@ -71,7 +154,7 @@

| Event | Description | Context | Primary Use |
|-------|-------------|---------|-------------|
| `payment.processing` | Crypto-to-fiat payment in progress | **subStatus values:** initiated, pending_internal_assessment, ongoing_checks, sending_fiat, fiat_sent, bounced | Track crypto-to-fiat payment status, update UI |

Check warning on line 157 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L157

Did you really mean 'subStatus'?

Check warning on line 157 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L157

Did you really mean 'pending_internal_assessment'?

Check warning on line 157 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L157

Did you really mean 'ongoing_checks'?

Check warning on line 157 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L157

Did you really mean 'sending_fiat'?

Check warning on line 157 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L157

Did you really mean 'fiat_sent'?

### Request Events

Expand All @@ -83,15 +166,15 @@

| Event | Description | Context | Primary Use |
|-------|-------------|---------|-------------|
| `compliance.updated` | KYC or agreement status changed | **kycStatus values:** not_started, pending, approved, rejected, retry_required<br/>**agreementStatus values:** not_started, pending, completed, rejected, failed | Update user permissions, notify status |

Check warning on line 169 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L169

Did you really mean 'kycStatus'?

Check warning on line 169 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L169

Did you really mean 'not_started'?

Check warning on line 169 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L169

Did you really mean 'retry_required'?

Check warning on line 169 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L169

Did you really mean 'agreementStatus'?

Check warning on line 169 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L169

Did you really mean 'not_started'?
| `payment_detail.updated` | Bank account verification status updated | States: approved, failed, pending | Enable fiat payments, update profiles |

### Secure Payment Events

| Event | Description | Context | Primary Use |
|-------|-------------|---------|-------------|
| `secure_payment.user_event` | Payer progressed through a step of the Secure Payment Page | **userEvent values:** wallet_connected, payment_sent_to_wallet, payment_approved_in_wallet | Real-time payer-funnel visibility, drop-off analytics |

Check warning on line 176 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L176

Did you really mean 'userEvent'?

Check warning on line 176 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L176

Did you really mean 'wallet_connected'?

Check warning on line 176 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L176

Did you really mean 'payment_sent_to_wallet'?

Check warning on line 176 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L176

Did you really mean 'payment_approved_in_wallet'?
| `secure_payment.access_rejected` | A wallet not on a payment's payer-wallet allowlist attempted to access or pay it | Incoming Secure Payments with `allowedPayerAddresses` | Monitor rejected payer attempts |

Check warning on line 177 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L177

Did you really mean 'allowlist'?

Sent to the same registered webhook endpoints as every other event — same Client ID scoping, `x-request-network-signature` HMAC verification, delivery headers, timeout, and 1s/5s/15s retry semantics described elsewhere on this page.

Expand All @@ -101,7 +184,7 @@
|-------------|---------|
| `wallet_connected` | The payer successfully 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/signed the payment in their wallet. `properties` includes the submission id (e.g. tx hash / user-operation hash) |

Check warning on line 187 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L187

Did you really mean 'tx'?

<Note>
`securePaymentToken` is the platform's correlation key, returned when the secure payment was created. `requestId` is present only when exactly one request is linked to the secure payment (see `requestIds` for the full list). `timestamp` is server-stamped on receipt. `occurredAt` and `properties` are **client-reported telemetry from the payer's browser** — useful for analytics, but not authoritative.
Expand All @@ -113,7 +196,7 @@

### Payer-wallet access rejections

`secure_payment.access_rejected` is generated server-side when a wallet that is not on an incoming payment's `allowedPayerAddresses` allowlist tries to access or pay it. It is not emitted for KYT decisions. See [Restrict payer wallets](/use-cases/restrict-payer-wallets) to configure the allowlist.

Check warning on line 199 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L199

Did you really mean 'allowlist'?

Check warning on line 199 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L199

Did you really mean 'allowlist'?

The event is sent to the payment's platform-wide and Client ID webhooks, not to an orchestrator webhook. Repeated attempts by the same wallet on the same payment are normally suppressed for 10 minutes. If every configured webhook endpoint fails, the next access attempt can trigger another notification.

Expand Down Expand Up @@ -210,11 +293,11 @@
- `requestId` / `requestID`: Unique identifier for the payment request
- `paymentReference`: Short reference, also unique to a request, used to link payments to the request
- `timestamp`: ISO 8601 formatted event timestamp
- `paymentProcessor`: Either `request-network` (crypto) or `request-tech` (fiat)

Check warning on line 296 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L296

Did you really mean 'crypto'?
- `payerAddress`: Resolved payer wallet — the on-chain sender for plain direct payments, or the resolved payer for recurring and intent-based flows (Secure Payment Page, LiFi, Safe, ERC-4337, multicall). `null` when it cannot be determined. Included on `payment.confirmed` and `payment.partial` events.

Check warning on line 297 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L297

Did you really mean 'multicall'?
- `payerEoaAddress`: The payer's connected wallet address. It can differ from `payerAddress` when a smart account is used. `null` when unavailable. Included on `payment.confirmed` and `payment.partial` events.

The `client_id.linked` and `kyt.screening.completed` examples below are delivered to an orchestrator endpoint. Register that endpoint with `x-orchestrator-key` as described in [Orchestrator webhooks](/orchestrators/webhooks).
The `client_id.linked` and `kyt.screening.completed` examples below are delivered to an orchestrator endpoint. Register that endpoint with `x-orchestrator-key` as described in [Orchestrator webhooks](#orchestrator-webhooks).

### Client ID linked

Expand Down Expand Up @@ -394,138 +477,14 @@
| 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. |

Check warning on line 480 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L480

Did you really mean 'lowercased'?
| `timestamp` | When Request Network emitted the event. |

Use `POST /v1/webhook/test` with `{ "eventType": "secure_payment.access_rejected" }` to test this event without a rejected access attempt.

## Implementation Examples

For a complete working example, see [Webhook reconciliation](/use-cases/webhook-reconciliation) which implements webhook handling for payment notifications.

<Tabs>
<Tab title="Express.js">
```javascript
import express from "express";
import crypto from "node:crypto";

const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// Use raw body parser to capture exact request bytes for signature verification
app.use(
express.raw({
type: "application/json",
verify: (req, _res, buf) => {
req.rawBody = buf;
},
})
);

app.post("/webhook/payment", async (req, res) => {
try {
// Verify signature against raw body
const signature = req.headers["x-request-network-signature"];
const deliveryId = req.headers["x-request-network-delivery"];
const rawBody = req.rawBody;

const expectedSignature = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");

if (!signature || !deliveryId) {
return res.status(400).json({ error: "Missing webhook headers" });
}

if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
return res.status(401).json({ error: "Invalid signature" });
}

// Parse JSON only after verifying signature
const body = JSON.parse(rawBody.toString("utf8"));
const isTest = req.headers["x-request-network-test"] === "true";

if (isTest) {
console.log("Received test webhook");
}

// Process webhook based on event type
const { event, requestId } = body;

switch (event) {
case "payment.confirmed":
await handlePaymentConfirmed(body);
break;
case "payment.processing":
await handlePaymentProcessing(body);
break;
case "compliance.updated":
await handleComplianceUpdate(body);
break;
case "secure_payment.access_rejected":
await recordPayerWalletRejection(
requestId,
body.attemptedPayerWalletAddress,
deliveryId,
);
break;
default:
console.log(`Unhandled event: ${event}`);
}

return res.status(200).json({ success: true });

} catch (error) {
console.error("Webhook processing error:", error);
return res.status(500).json({ error: "Processing failed" });
}
});
```
</Tab>

<Tab title="Next.js">
```javascript
// app/api/webhook/route.ts
import crypto from "node:crypto";
import { NextResponse } from "next/server";
## Process webhook deliveries

export async function POST(request: Request) {
try {
// Read raw body for signature verification
const rawBody = await request.text();
const signature = request.headers.get("x-request-network-signature");
const expectedSignature = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");

if (!signature || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}

// Parse JSON after verifying signature
const body = JSON.parse(rawBody);

// Process webhook
const { event, requestId } = body;

// Your business logic here
await processWebhookEvent(event, body);

return NextResponse.json({ success: true }, { status: 200 });

} catch (error) {
console.error("Webhook error:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
```
</Tab>
</Tabs>
For a signature-verifying handler that safely acknowledges test deliveries and retries, see [Webhook reconciliation](/use-cases/webhook-reconciliation).
Comment thread
MantisClone marked this conversation as resolved.
Comment thread
MantisClone marked this conversation as resolved.

## Testing

Expand All @@ -542,28 +501,12 @@

Or call it interactively from the [Auth API Scalar docs](https://auth.request.network/open-api/#tag/webhook/POST/v1/webhook/test).

Test deliveries arrive at all active webhooks for that Client ID and include the `x-request-network-test: true` header so handlers can branch on test vs real.

### Test Webhook Identification
Test webhooks include the `x-request-network-test: true` header:

```javascript
app.post("/webhook", (req, res) => {
const isTest = req.headers["x-request-network-test"] === "true";

if (isTest) {
console.log("Received test webhook");
// Handle test scenario
}

// Process normally...
});
```
Test deliveries arrive at all active webhooks for that Client ID and include the `x-request-network-test: true` header. They use placeholder data, so acknowledge a verified test delivery without changing application state. See [Webhook reconciliation](/use-cases/webhook-reconciliation) for a safe handler pattern.

## Best Practices

### Error Handling
- **Implement idempotency:** Use delivery IDs to prevent duplicate processing

Check warning on line 509 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L509

Did you really mean 'idempotency'?
- **Graceful degradation:** Handle unknown event types without errors

### Performance
Expand All @@ -584,22 +527,22 @@
- Confirm the webhook is `active` via `GET /v1/webhook` (toggle with `PUT /v1/webhook/:id`)

### Debugging Tips
- Use ngrok request inspector to see raw webhook data

Check warning on line 530 in api-reference/webhooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

api-reference/webhooks.mdx#L530

Did you really mean 'ngrok'?
- Monitor retry counts in headers to identify issues
- Fire test deliveries via `POST /v1/webhook/test`

## Related Documentation

<CardGroup cols={2}>
<Card title="Webhooks & Events" href="/api-features/webhooks-events">
<Card title="Webhooks & Events" href="/api-features/webhooks-events" icon="bell">
High-level webhook concepts and workflow
</Card>

<Card title="Webhook reconciliation" href="/use-cases/webhook-reconciliation">
<Card title="Webhook reconciliation" href="/use-cases/webhook-reconciliation" icon="webhook">
Complete webhook implementation example
</Card>

<Card title="Authentication" href="/api-reference/authentication">
<Card title="Authentication" href="/api-reference/authentication" icon="shield">
API credential setup and webhook security
</Card>

Expand Down
6 changes: 5 additions & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,10 @@
{
"source": "/webhooks",
"destination": "/api-features/webhooks-events"
},
{
"source": "/orchestrators/webhooks",
"destination": "/api-reference/webhooks"
}
],
"navigation": {
Expand Down Expand Up @@ -546,10 +550,10 @@
"group": "Orchestrators",
"pages": [
"orchestrators/overview",
"orchestrators/webhooks",
"orchestrators/fees",
"orchestrators/client-id-linking",
"orchestrators/kyt-plans",
"orchestrators/webhooks",
"orchestrators/whitelabel-branding"
]
}
Expand Down
4 changes: 2 additions & 2 deletions orchestrators/client-id-linking.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

All linking endpoints use the `x-orchestrator-key` header.

If you use hosted onboarding, [register an orchestrator webhook](/orchestrators/webhooks) before you send the onboarding URL. It receives the resulting client ID after the platform completes the flow.
If you use hosted onboarding, [register an orchestrator webhook](/api-reference/webhooks#orchestrator-webhooks) before you send the onboarding URL. It receives the resulting client ID after the platform completes the flow.

<Note>
A client ID can be linked to one orchestrator only. A second link request is rejected, whether it is for the same orchestrator or a different one. If you need to check whether a link request succeeded, list your linked client IDs instead of retrying it. Unlinking removes the active connection, but does not make the client ID linkable again.

Check warning on line 15 in orchestrators/client-id-linking.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/client-id-linking.mdx#L15

Did you really mean 'Unlinking'?
</Note>

## Link an existing client ID
Expand All @@ -34,7 +34,7 @@
"clientId": "cli_PLATFORM_CLIENT_ID",
"status": "active"
},
"alreadyLinked": false

Check warning on line 37 in orchestrators/client-id-linking.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/client-id-linking.mdx#L37

Did you really mean 'alreadyLinked'?
}
```

Expand Down Expand Up @@ -71,7 +71,7 @@
-H "x-orchestrator-key: orc_YOUR_ORCHESTRATOR_KEY"
```

Unlinking does not delete the client ID, but it removes the active association with your orchestrator. As noted above, it does not make that client ID linkable again.

Check warning on line 74 in orchestrators/client-id-linking.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/client-id-linking.mdx#L74

Did you really mean 'Unlinking'?

## Onboard a platform with a link intent

Expand Down Expand Up @@ -121,7 +121,7 @@
3. Review your screening plan, or choose a screening preference when you did not provide one.
4. Confirm the connection to your orchestrator.

After confirmation, Request Network creates a new `cli_*` client ID, copies any allowed domains from the intent, links it to your orchestrator, and binds it to the platform's active payment destination. Active orchestrator webhooks receive a [`client_id.linked` event](/orchestrators/webhooks) with the client ID, link identifiers, and destination details. Direct links do not send this event.
After confirmation, Request Network creates a new `cli_*` client ID, copies any allowed domains from the intent, links it to your orchestrator, and binds it to the platform's active payment destination. Active orchestrator webhooks receive a [`client_id.linked` event](/api-reference/webhooks#client-id-linked) with the client ID, link identifiers, and destination details. Direct links do not send this event.

<Note>
A link intent is single-use and expires after two days. Create a new intent if the platform has not completed the flow before it expires.
Expand Down
4 changes: 2 additions & 2 deletions orchestrators/kyt-plans.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
When you create a [hosted onboarding link](/orchestrators/client-id-linking#onboard-a-platform-with-a-link-intent), you choose who controls transaction screening (KYT) for the resulting linked client ID:

- **Orchestrator-controlled** — include a `kyt` plan in the link intent. The platform can review the plan, but cannot change it during onboarding or later in the Request dashboard.
- **Platform-controlled** — omit `kyt`. During onboarding, the platform chooses Hypernative, Merkle Science, or no screening. It can update that choice later.

Check warning on line 11 in orchestrators/kyt-plans.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/kyt-plans.mdx#L11

Did you really mean 'Hypernative'?

Check warning on line 11 in orchestrators/kyt-plans.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/kyt-plans.mdx#L11

Did you really mean 'Merkle'?

The selection is stored on the client ID created during onboarding. It does not change the KYT policy configured on the payment destination.

Expand Down Expand Up @@ -72,7 +72,7 @@

## Receive screening results

Your active [orchestrator webhooks](/orchestrators/webhooks#receive-kyt-screeningcompleted) receive `kyt.screening.completed` after a linked payment reaches a definitive screening result. The event is sent for `approved` and `rejected` results, not provider errors.
Your active [orchestrator webhooks](/api-reference/webhooks#kyt-screening-completed) receive `kyt.screening.completed` after a linked payment reaches a definitive screening result. The event is sent for `approved` and `rejected` results, not provider errors.

Test your receiver with the existing webhook test endpoint:

Expand All @@ -92,7 +92,7 @@
Create the hosted onboarding link that carries an orchestrator KYT plan.
</Card>

<Card title="Orchestrator webhooks" href="/orchestrators/webhooks" icon="webhook">
<Card title="Webhooks" href="/api-reference/webhooks#orchestrator-webhooks" icon="webhook">
Verify and process `kyt.screening.completed` events.
</Card>
</CardGroup>
6 changes: 3 additions & 3 deletions orchestrators/overview.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Orchestrators overview"
description: "Orchestrators are fee and branding partners in Request Network: link client IDs, configure fees, and apply whitelabel branding across your platform."

Check warning on line 3 in orchestrators/overview.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/overview.mdx#L3

Did you really mean 'whitelabel'?
---

## What is an orchestrator?
Expand All @@ -9,11 +9,11 @@

- **Link client IDs** — associate the developer [Client IDs](/api-features/client-id-management) (`cli_*` tokens) of the platforms you serve with your orchestrator.
- **Create payment links** — use your key with a linked client ID to create incoming payment links and outgoing payout links for a platform.
- **Receive webhooks** — receive signed `client_id.linked` notifications after a platform completes hosted onboarding and `kyt.screening.completed` notifications after a definitive screening result.
- **Receive webhooks** — receive signed `client_id.linked` notifications after a platform completes hosted onboarding and `kyt.screening.completed` notifications after a definitive screening result. See [Orchestrator webhooks](/api-reference/webhooks#orchestrator-webhooks).
- **Configure fees** — set [orchestrator fees](/orchestrators/fees) (and per-client-ID overrides) that apply to payments made under those client IDs.
- **Apply branding** — give the hosted [Secure Payment](/tools/secure-payments) experience your own [whitelabel branding](/orchestrators/whitelabel-branding).

This is aimed at platforms, PSPs, and partners who orchestrate payments on behalf of multiple downstream merchants and want consistent fees and branding across them.

Check warning on line 16 in orchestrators/overview.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/overview.mdx#L16

Did you really mean 'PSPs'?

<Note>
"Orchestrator" here is the formal fee/branding partner account described on this page. It is different from using a Client ID with a payment destination, described in [Client ID Management](/api-features/client-id-management#using-a-client-id-with-a-payment-destination).
Expand Down Expand Up @@ -60,15 +60,15 @@
| `DELETE /v2/orchestrators/webhooks/:id` | Deactivate a webhook endpoint |
| `POST /v2/orchestrators/webhooks/test` | Send a test event to active webhook endpoints |
| `POST /v2/orchestrators/fee-configs` | Create an orchestrator fee or per-client-ID override |
| `GET /v2/orchestrators/fee-configs` | List your fee configs (optionally `?clientId`) |

Check warning on line 63 in orchestrators/overview.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/overview.mdx#L63

Did you really mean 'configs'?
| `PATCH /v2/orchestrators/fee-configs/:id` | Update a fee config |
| `DELETE /v2/orchestrators/fee-configs/:id` | Disable a fee config |

See [Client ID linking](/orchestrators/client-id-linking), [Whitelabel branding](/orchestrators/whitelabel-branding), [Orchestrator webhooks](/orchestrators/webhooks), and [Orchestrator fees](/orchestrators/fees) for details.
See [Client ID linking](/orchestrators/client-id-linking), [Whitelabel branding](/orchestrators/whitelabel-branding), [Orchestrator webhooks](/api-reference/webhooks#orchestrator-webhooks), and [Orchestrator fees](/orchestrators/fees) for details.

## How orchestrators apply at payment time

**Fees** are applied only when the secure payment is created with **paired authentication** — both your `x-orchestrator-key` and the platform's `x-client-id` headers. A client-ID-only call cannot carry an orchestrator key (it is rejected), so it receives no orchestrator fee. The orchestrator's active fee configuration is resolved and baked into the payment at creation time:

Check warning on line 71 in orchestrators/overview.mdx

View check run for this annotation

Mintlify / Mintlify Validation (requestnetwork) - vale-spellcheck

orchestrators/overview.mdx#L71

Did you really mean 'orchestrator's'?

```bash
curl -X POST "https://api.request.network/v2/secure-payments" \
Expand All @@ -91,7 +91,7 @@
Link client IDs directly or via onboarding link intents.
</Card>

<Card title="Orchestrator webhooks" href="/orchestrators/webhooks" icon="webhook">
<Card title="Orchestrator webhooks" href="/api-reference/webhooks#orchestrator-webhooks" icon="webhook">
Receive signed onboarding and KYT screening notifications.
</Card>

Expand Down
Loading