Webhooks
Maven sends an HTTP POST to your webhook URL when a payment session completes or fails. This is the recommended way to get payment results back into your system.Voice and chat widget both use the same webhook. One webhook URL per project, one handler in your code — it processes both channels. Use the
caller field to distinguish: it’s the customer’s phone number for voice, and null for chat.When Webhooks Fire
Webhooks are sent when a session reaches a terminal payment status:
Webhooks are not sent for
expired, cancelled, or abandoned sessions — poll the GET session endpoint for those.
Configuring Your Webhook URL
Set a webhook URL per app in the Maven Dashboard:- Navigate to your app
- Go to the Settings tab
- Enter your webhook URL (must be HTTPS in production)
- Save
Verifying Webhook Signatures
Your webhook URL is public, so anyone could POST a forged event to it. Maven signs every webhook with an HMAC so you can confirm it genuinely came from us and wasn’t altered in transit. Verification is optional but strongly recommended for production.Signing is backward compatible — it only adds a header. If you don’t verify it, your existing handler keeps working unchanged. Adopt verification whenever you’re ready.
The signing secret
Each app has its own signing secret (formatwhsec_…). Find it in the Dashboard under App → Settings → Webhook → Signing secret, where you can reveal, copy, and rotate it.
The Maven-Signature header
Every webhook request includes:
The timestamp is part of the signed content, so it can’t be altered without breaking the signature — this is what protects you against replay attacks.
How to verify
- Read the raw request body — the exact bytes, before any JSON parsing/re-serialization.
- Parse
tandv1from theMaven-Signatureheader. - Compute
HMAC_SHA256(secret, "{t}." + raw_body). - Constant-time compare it against
v1. - Reject if
tis older than your tolerance (e.g. 5 minutes) to block replays.
- Python (FastAPI)
- Node (Express)
Payload Format
All webhook payloads share the same top-level fields. Theprocessor object varies by gateway and mode — see Processor Fields by Gateway for the full specs.
Voice vs Chat
The payload is almost identical for voice and chat — only one field differs:calleris the customer’s phone number for voice sessions, andnullfor chat sessions (no phone involved)
status, processor, card_brand, card_last4, error codes — is the same. A single webhook handler works for both.
- Chat (Widget)
- Voice (Phone)
Full examples by gateway
- Stripe (Charge)
- Stripe (Tokenize)
- Braintree (Charge)
- Braintree (Tokenize)
- Shift4 (Charge)
- Shift4 (Tokenize)
- Fiserv (Charge)
- Fiserv (Tokenize)
Field Reference
Error Object (failures only)
Processor Fields by Gateway
Theprocessor object contains different fields depending on the gateway and mode (charge vs tokenize).
- Stripe
- Braintree
- Shift4
- Fiserv
Charge mode:
Tokenize mode:
Handling Webhooks
Your webhook endpoint should:- Return a
200status code quickly (within 5 seconds) - Process the payload asynchronously if needed
- Be idempotent — use
session_idto deduplicate
Best Practices
Always return 200 quickly
Always return 200 quickly
Return a
200 response immediately and process the webhook asynchronously. Maven uses a 5-second delivery timeout; if your endpoint is slower, the request is treated as failed and retried.Use idempotent handlers
Use idempotent handlers
Use the
session_id to deduplicate — check if you’ve already processed this session before acting on it.Verify the signature
Verify the signature
Confirm the event came from Maven by verifying the
Maven-Signature header — see Verifying Webhook Signatures. As an additional check, you can also confirm the session_id belongs to your organization via the API:Handle failures gracefully
Handle failures gracefully
If your endpoint returns a 5xx or times out, Maven retries up to 3 times with exponential backoff (1s, 2s, 4s). A 4xx response is treated as a rejection and is not retried. If all attempts fail the webhook is dropped, so for critical flows also poll the session status as a fallback.
