Setting up webhooks
Configure your webhook URL
Contact the Maash team to register your
webhook_url. All checkout events will be delivered to this URL once configured.Ensure your endpoint meets requirements
Your endpoint must:
- Accept
POSTrequests with a JSON body - Return a
2xxstatus code within 30 seconds - Be publicly accessible over HTTPS
Verify webhook signatures
Verify the
X-Maash-Signature header on every delivery to confirm authenticity. See Verifying signatures below.Webhook payload
Every webhook delivery uses a consistent envelope format with anevent, action, and body:
Top-level fields
| Field | Type | Description |
|---|---|---|
id | string | Unique webhook identifier (ULID with wh_ prefix). |
event | string | Always "checkout". |
action | string | "create" for new sessions, "update" for all subsequent changes. |
timestamp | string | ISO 8601 timestamp of when the webhook was generated. |
version | string | Payload schema version. Currently "1.0.0". |
Body fields
| Field | Type | Description |
|---|---|---|
transaction_id | string | Maash transaction ID for this checkout session. |
merchant_id | string | Your Maash merchant identifier. |
ext_transaction_id | string | Your external transaction ID (passed when creating the session). |
amount | string | Payment amount in USD. |
currency | string | Currency code. Always "USD". |
status | string | Current checkout status (see table below). |
Statuses and actions
Webhooks are sent at each stage of the checkout lifecycle:| Status | Action | Trigger |
|---|---|---|
init | create | Checkout session created. |
awaiting_payment | update | Customer selected a token and chain for payment. |
pending | update | Payment detected on-chain, bridge pending. |
processing | update | Bridge accepted, funds being transferred. |
completed | update | Payment confirmed and settled to your wallet. |
failed | update | Payment failed, refunded, cancelled, or rejected. |
Webhook headers
Each webhook request includes these headers:| Header | Description |
|---|---|
Content-Type | application/json |
X-Maash-Signature | HMAC-SHA256 signature of the payload. |
X-Maash-Timestamp | Unix timestamp of when the webhook was sent. |
X-Maash-Idempotency-Key | Unique key in the format {transaction_id}_{status}_v1. |
Verifying signatures
Verify theX-Maash-Signature header to confirm that a webhook came from Maash. The signature is computed as:
Timestamp validation
Reject webhooks with timestamps older than 5 minutes to prevent replay attacks:Retry policy
If your endpoint returns a non-2xx status code or does not respond within 30 seconds, Maash retries the delivery with exponential backoff:| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 15 minutes |
| 5 | 1 hour |
| 6 (final) | 2 hours |
Idempotency
Each webhook delivery includes anX-Maash-Idempotency-Key header. Use this key to deduplicate events in case of retries.
The key format is {transaction_id}_{status}_v1. For example: cs_01ARZ3NDEKTSV4RRFFQ69G5FAV_completed_v1.
Best practices
Respond quickly
Respond quickly
Return a
200 response as soon as you receive the webhook, then process the
event asynchronously. This avoids timeouts and unnecessary retries.Verify signatures
Verify signatures
Always validate the
X-Maash-Signature before processing. Reject any
delivery that fails verification.Handle duplicates
Handle duplicates
Use the
X-Maash-Idempotency-Key to prevent double-processing. Store
processed keys and skip events you have already handled.Log deliveries
Log deliveries
Store the raw payload for debugging and auditing. This helps diagnose issues
if a webhook handler behaves unexpectedly.
Use HTTPS
Use HTTPS
Webhook URLs must use HTTPS in production. HTTP endpoints will be rejected.
Next steps
Checkout flow
Understand the full payment lifecycle and session statuses.
Error handling
Handle API errors and implement retry strategies.
Testing
Test webhook delivery and signature verification locally.
Authentication
Learn about API keys and session tokens.
