POST /api/webhooks/payment
Receive payment lifecycle events from the payment provider. Route name:webhooks.paymentPath:
/api/webhooks/payment (note: no /v1 prefix — legacy path maintained)Authentication: HMAC signature verification (see below)
CSRF: Exempt
This endpoint is exempt from CSRF verification. Access control is enforced exclusively through HMAC signature validation on every incoming request.
Signature verification
Every request must include anX-Signature header containing an HMAC-SHA256 signature of the raw request body.
The server verifies the signature using the secret configured in PAYMENT_WEBHOOK_SECRET (.env):
X-Signature header is missing or does not match, the endpoint returns 403 Forbidden.
Request format
HMAC-SHA256 hex signature of the raw request body.
Event type identifier (see supported events below).
Event payload. Structure varies by event type.
Supported events
| Event type | Description |
|---|---|
| Payment confirmed | Order payment successfully completed |
| Payment rejected | Payment attempt failed or was declined |
| Subscription created | New subscription activated |
| Subscription cancelled | Subscription terminated |
| Subscription renewed | Subscription billing cycle renewed |
Event type strings are defined by the payment provider integration. Check the
HandlePaymentWebhookAction domain action for the full list of handled event types.Response
| Status | Body | Meaning |
|---|---|---|
200 OK | {"status": "ok"} | Event processed successfully |
202 Accepted | {"status": "ignored"} | Event received but not processed (unknown type) |
403 Forbidden | {"message": "Invalid signature"} | Signature missing or invalid |
422 Unprocessable Entity | {"status": "invalid"} | Event payload failed domain validation |
500 Internal Server Error | {"status": "error"} | Unexpected processing error |
Idempotency
All incoming webhook events are persisted to thewebhook_logs table via the WebhookLog model before processing. This provides:
- Idempotency: Duplicate events with the same
external_event_idcan be detected by querying the log. - Audit trail: Every received payload is stored for forensic debugging.
- Replay support: Failed events can be replayed from the log.
WebhookLog model
| Column | Type | Description |
|---|---|---|
id | integer | Auto-increment primary key |
provider | string | Payment provider identifier |
external_event_id | string | Unique event ID from the provider |
event_type | string | Normalized event type string |
payload | JSON | Full raw payload |
created_at | datetime | When the event was received |