Webhooks
Register HTTPS callbacks for payment and funding events. Delivery is signed, SSRF-safe, retried via an outbox, and verifiable with the secret returned on create.
Same flow in MCP: rill_webhooks
Auth
Owner Supabase JWT required. Send Idempotency-Key on create. Save the signing secret from the create response, it is required to verify X-Rill-Signature on every delivery.
Authorization: Bearer <owner JWT>Featured endpoints
Register a webhook
POST /webhooksRegister a callback URL for events such as payment.succeeded and funding.paid. Localhost callbacks are allowed outside production. List registered endpoints with GET /webhooks.
Request body
What to save
Save the webhook id and signing secret. Verify every delivery as HMAC-SHA256 of `{X-Rill-Webhook-Id}.{X-Rill-Timestamp}.{raw body}` (hex), header X-Rill-Signature: v1,<hex>, plus X-Rill-Timestamp within 300 seconds. Use the raw bytes; do not re-serialize JSON.
- Catalog events with GET /webhooks/events.
- Test with POST /webhooks/:id/test (signed {test:true} event); retry with …/deliveries/:deliveryId/retry.
- MCP twin: rill_webhooks action=create|list|test|delete.
All endpoints
Signing and events
- Sign: HMAC-SHA256 over `{X-Rill-Webhook-Id}.{X-Rill-Timestamp}.{raw body}`, hex digest, header X-Rill-Signature: v1,<hex> (comma, not equals). Reject if |now - timestamp| > 300 seconds.
- HTTP body is the signed JSON envelope {id, type, created_at, data}. X-Rill-Webhook-Id is envelope.id. Verify the raw body bytes.
- payment.succeeded data includes ok, type, rail (mpp|x402|rill), receipt_id, resource_id, short_id, path_or_tool, metadata (the pay link SKU: sku_kind one_shot|credit_topup, credits, credit_unit, plus anything you stored), seller_id, amount, platform_fee, stripe_payment_intent_id, seller_balance.
- Example envelope: {"id":"evt_…","type":"payment.succeeded","created_at":"2026-09-09T12:00:00.000Z","data":{"ok":true,"type":"resource","rail":"x402","receipt_id":"rcpt_…","resource_id":"res_…","short_id":"AB12CD","path_or_tool":"/get_full_dossier","metadata":{"sku_kind":"one_shot"},"seller_id":"sel_…","amount":"34.00","platform_fee":"0.00","stripe_payment_intent_id":"pi_…"}}
- Credit top-up example data: {"rail":"mpp","path_or_tool":"/credits/500","metadata":{"sku_kind":"credit_topup","credits":500,"credit_unit":"api_calls"},"amount":"25.00"}. Add metadata.credits to the buyer identified by your own request context; the receipt_id is your dedupe key.
- Node verify: createHmac('sha256', secret).update(`${eventId}.${timestamp}.${rawBody}`).digest('hex') then timingSafeEqual against the v1, prefix.
- Events include payment.succeeded, payment.failed, transfer.received, funding.paid, withdrawal.paid, withdrawal.failed, vw.revoked, allowance.reset, seller.withdrawn, resource.updated.