diff --git a/use-cases/quickstart.mdx b/use-cases/quickstart.mdx index 4c4b3e7..c7aecd2 100644 --- a/use-cases/quickstart.mdx +++ b/use-cases/quickstart.mdx @@ -186,134 +186,7 @@ Save the `clientId` value (e.g. `cli_nz1bj41szV2fvjm9pbxdIhro3ld4x4`) — you'll ## Step 4: Register a Webhook -Webhooks let you receive real-time notifications when a payment is completed (or partially paid) for your payment links — no polling required. - -Webhooks are scoped to the Client ID that creates them. Any payment link created with that Client ID will trigger the webhook. The webhook payload includes the `clientId` field so you can identify which Client ID the payment was associated with. - -### Creating a webhook - -Open [auth.request.network/open-api](https://auth.request.network/open-api/#tag/webhook/POST/v1/webhook) and call: - -```http -POST https://auth.request.network/v1/webhook -x-client-id: -Content-Type: application/json - -{ - "url": "https://mydomain.com/webhook" -} -``` - -**Example response (201 Created):** - -```json -{ - "id": "01KJC2WX8EH4MP3DHZB2YQ7N9G", - "secret": "f3c189a4b5e6d7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2" -} -``` - - -The `secret` is only returned once at creation. Store it securely — you cannot retrieve it again. Use HTTPS in production. `localhost` URLs are accepted for local testing. - - -### Managing webhooks - -Use the same Scalar docs page to list, toggle, or delete webhooks (all accept `x-client-id`): - -| Method | Path | Purpose | -| --- | --- | --- | -| `GET` | `/v1/webhook` | List webhooks for this Client ID | -| `PUT` | `/v1/webhook/:webhookId` | Toggle active / inactive | -| `DELETE` | `/v1/webhook/:webhookId` | Permanently delete | -| `POST` | `/v1/webhook/test` | Body `{ "eventType": "payment.confirmed" }` — fire a test delivery | - -### Verifying webhook signatures - -Every webhook request includes a signature header so you can verify it came from Request Network: - -| Header | Description | -| --- | --- | -| `x-request-network-signature` | HMAC-SHA256 of the raw JSON body, signed with your webhook secret | -| `x-request-network-delivery` | Unique delivery ID — use as an idempotency key | -| `x-request-network-retry-count` | Retry attempt number (`0`–`3`) | -| `x-request-network-test` | `true` only for test deliveries via `/v1/webhook/test` | - -To verify, compute `HMAC-SHA256(rawBody, webhookSecret)` and compare it to `x-request-network-signature` using a constant-time comparison. - -```typescript -import { createHmac, timingSafeEqual } from "node:crypto"; - -function verify(rawBody: string, signature: string | undefined, secret: string) { - if (!signature) return false; - const expected = createHmac("sha256", secret).update(rawBody).digest("hex"); - const a = Buffer.from(expected, "hex"); - const b = Buffer.from(signature, "hex"); - return a.length === b.length && timingSafeEqual(a, b); -} -``` - -Always verify against the **raw** request body before parsing. - -**Retries:** up to 3 retries (4 attempts total), default delays 1s / 5s / 15s, triggered on any non-2xx response, timeout, or connection error. - -### Webhook events for payment links - -When a payer completes a payment on a payment link you created, your webhook receives a `payment.confirmed` event (or `payment.partial` for partial payments). - -**Example `payment.confirmed` payload:** - -```json -{ - "event": "payment.confirmed", - "requestId": "01de2a889ee629c15b71b5d7964e3a7e87638c886be75bf1b9d2c1fbe64cf855fb", - "paymentReference": "0xabc123...", - "payee": "0x6923831ACf5c327260D7ac7C9DfF5b1c3cB3C7D7", - "amount": "10.0", - "totalAmountPaid": "10.0", - "expectedAmount": "10.0", - "timestamp": "2026-03-02T20:15:00.000Z", - "txHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", - "network": "sepolia", - "currency": "FAU", - "paymentCurrency": "FAU", - "clientId": "cli_nz1bj41szV2fvjm9pbxdIhro3ld4x4", - "origin": "https://mydomain.com" -} -``` - -Key fields to look for: - -| Field | Description | -| --- | --- | -| `event` | `payment.confirmed` (fully paid) or `payment.partial` (partial payment) | -| `requestId` | The request ID from when you created the payment link | -| `clientId` | The Client ID used to create the payment link — use this to route events if you have multiple Client IDs | -| `amount` | The amount paid in this transaction | -| `totalAmountPaid` | Cumulative amount paid so far | -| `expectedAmount` | The total amount expected | -| `txHash` | On-chain transaction hash | -| `network` | The blockchain network | -| `currency` | The token used for payment | - -### All supported webhook events - -| Event | Description | -| --- | --- | -| `payment.confirmed` | Payment fully confirmed | -| `payment.partial` | Partial payment received | -| `payment.failed` | Payment failed | -| `payment.refunded` | Payment refunded | -| `payment.processing` | Offramp processing started | -| `request.recurring` | A recurring request fired | -| `payment_detail.updated` | Payment detail metadata changed | -| `compliance.updated` | Compliance status changed | -| `secure_payment.user_event` | Payer progressed through a Secure Payment Page step (`userEvent`: `wallet_connected`, `payment_sent_to_wallet`, `payment_approved_in_wallet`) — funnel telemetry, not a settlement signal | -| `secure_payment.access_rejected` | A wallet not on a Secure Payment's payer-wallet allowlist tried to access or pay it | - - -`secure_payment.user_event` is best-effort browser telemetry. The payer's browser can fail to reach the API, and retries begin only once the API has accepted the event — so a missing event is not evidence that the payer skipped the step. Use `payment.confirmed` for settlement and reconciliation. - +Register a webhook for your Client ID to receive `payment.confirmed` when a payment completes. See the [Webhooks reference](/api-reference/webhooks) for endpoint setup, recipient routing, payloads, and signature verification. ## Step 5: Create a Secure Payment (Payment Link)