Webhooks
The API receives inbound webhooks from Bridge to observe fiat and off-ramp events. Handler: apps/api/src/webhooks/bridge.ts.
Endpoint
POST /webhooks/bridge
Unauthenticated by JWT — verified by RSA-SHA256 signature over <timestamp>.<raw body>.
Verification
Events handled
| Event | Handler | What it does |
|---|---|---|
customer.updated | handleCustomerUpdated | Updates kyc_verifications.status when Bridge marks a customer approved/rejected. |
virtual_account.activity.funds_received | handleVirtualAccountActivity | Creates a transactions row (type = deposit) for the inbound fiat, status = pending. |
virtual_account.activity.payment_submitted | handleVirtualAccountActivity | Advances the deposit's status toward completion. |
virtual_account.activity.payment_processed | handleVirtualAccountActivity | Marks deposit completed. |
liquidation_address.drain_completed | handleLiquidationDrain | Marks the linked PIX / withdraw transaction completed; stores pixEndToEndId / bridgeTransferId. |
liquidation_address.drain_failed | handleLiquidationDrain | Marks the transaction failed with failureReason. |
Any other event types are recorded in webhook_events but otherwise ignored.
Idempotency
Every webhook is recorded in webhook_events before processing (unique on bridgeEventId). A replayed webhook returns 200 immediately without side effects. The handler updates processedAt only on successful completion — a mid-processing crash lets the retry re-run the handler.
Configuring Bridge
- URL:
https://<api-host>/webhooks/bridge - Secret: the RSA public key/secret pair from the Bridge dashboard; store the verification secret as the
BRIDGE_WEBHOOK_SECRETCloudflare secret. - Events to subscribe to:
customer.*,virtual_account.activity.*,liquidation_address.drain_*at minimum.
Debugging
- Look in the
webhook_eventstable for the raw payload, event type, and processing timestamp. - Cloudflare Workers logs (
wrangler tail) show signature failures and handler errors.