Modulr & Griffin Inbound Webhook Handlers
Modulr & Griffin Inbound Webhook Handlers
Introduced in v1.0.39
The Direct Debit service exposes two public webhook endpoints that receive signed event payloads from Modulr and Griffin respectively. These handlers form the real-time nervous system of the fund flow — every mandate lifecycle event and every payment confirmation arrives through one of these routes.
Overview
| Endpoint | Provider | Purpose |
|---|---|---|
POST /api/webhooks/modulr | Modulr | Mandate status changes, collection outcomes |
POST /api/webhooks/griffin | Griffin | Payment received / payment sent confirmations |
Modulr Webhook Handler
Endpoint: POST /api/webhooks/modulr
Supported Events
Mandate Status Changes (AUDDIS)
| Event | Description |
|---|---|
mandate.auddis_accepted | The mandate has been accepted by the AUDDIS scheme. The mandate record is updated to active. |
mandate.auddis_rejected | The mandate was rejected during AUDDIS processing. The mandate record is updated to failed and downstream alerting is triggered. |
Collection Events
| Event | Description |
|---|---|
collection.paid | Funds have been successfully debited from the tenant's account. Triggers the sweep-to-holding flow. |
collection.failed | The collection attempt failed (e.g. insufficient funds). The collection record is updated and an alert is raised. |
collection.returned | A previously paid collection has been returned (clawback). The holding account reserve logic is re-evaluated. |
Signature Validation
Every inbound request is validated against Modulr's signed payload before processing begins. Requests that fail signature verification receive a 401 Unauthorized response and are not processed further.
Griffin Webhook Handler
Endpoint: POST /api/webhooks/griffin
Supported Events
Payment Received
Fired when funds arrive in the Griffin DD holding account — typically following a successful Modulr collection and subsequent sweep. Upon receipt:
- The holding account balance record is updated.
- A hold-period timer is initiated via Inngest.
- The clawback reserve requirement is evaluated.
Payment Sent
Fired when an outbound payment from the Griffin holding account to an agent's client account is confirmed. Upon receipt:
- The forwarding record is marked complete.
- The holding account balance is decremented.
- Any downstream reconciliation events are dispatched.
Signature Validation
Griffin webhook payloads are verified using Griffin's signing mechanism before any state changes are made. Invalid signatures result in a 401 Unauthorized response.
Idempotency
Both handlers are fully idempotent. Each webhook event carries a unique identifier that is checked against previously processed events before any action is taken. Re-delivered events (e.g. due to provider retries) are safely ignored without causing duplicate records, double-triggered jobs, or inconsistent balance state.
Downstream Event Flow
After updating database records, each handler dispatches one or more Inngest events to continue the relevant workflow asynchronously:
Modulr collection.paid
→ DB: mark collection as paid
→ Inngest: trigger sweep-to-holding job
Modulr collection.failed / returned
→ DB: update collection status
→ Inngest: trigger alert + reserve re-evaluation
Modulr mandate.auddis_accepted / rejected
→ DB: update mandate status
→ Inngest: notify consuming application (e.g. agentOS gatekeeping)
Griffin payment_received
→ DB: update holding account balance
→ Inngest: start hold-period timer
Griffin payment_sent
→ DB: mark forwarding as complete
→ Inngest: trigger reconciliation
Security Notes
- Webhook endpoints are public but not authenticated via the standard API key mechanism — they are secured exclusively through provider-side payload signing.
- Never expose raw webhook payloads in logs. Both handlers should be treated as an ingress boundary and only trusted after signature verification passes.
- Both endpoints return
200 OKpromptly to acknowledge receipt; all processing happens asynchronously via Inngest to avoid provider-side timeout retries.