RapidCents
Webhooks
RapidCents sends server-to-server POST notifications when checkout sessions and payments change. Treat verified webhooks as the source of truth for settlement, voids, and refunds—return URLs and iframe messages are UX signals only.
Complements checkout guides
Session creation and payment UI are covered in the checkout overview. This page covers receiving and processing outbound events.
Endpoint & headers
Configure RapidCents to POST JSON to your HTTPS endpoint. In this demo app:
Replace {APP_URL} with your public base URL (must match the active gateway environment).
Content-Type
Yes
Signature or X-Signature
When secret set
X-Gateway-Environment-Id
Optional
Respond with HTTP 2xx and a small JSON body (for example {"ok": true}) promptly. Defer slow work to a queue if needed.
Signature validation
When webhook_secret is stored on the gateway environment, the demo app requires a valid signature. Algorithm: hash_hmac('sha256', raw_body, webhook_secret) compared with constant-time equality to the header value.
expected = HMAC_SHA256(raw_request_body, webhook_secret)
provided = request.header("Signature") ?? request.header("X-Signature")
if webhook_secret is set and not secure_compare(expected, provided):
return 401
Envelope structure
Current RapidCents outbound webhooks use an envelope with eventType, identifiers, and a nested payload object. Event types are prefixed with rapidcents. (for example rapidcents.payment.succeeded); handlers typically strip that prefix.
eventType
string
webhookId
string
notificationId
string
eventDate
string
payload
object
{
"eventType": "rapidcents.payment.succeeded",
"webhookId": "wh_01HXABCDEF",
"notificationId": "ntf_01HXABCDEF",
"eventDate": "2026-05-22T14:30:00Z",
"payload": {
"sourceName": "checkout_session",
"sourceId": "550e8400-e29b-41d4-a716-446655440000",
"sessionToken": "cs_live_a1b2c3",
"sessionStatus": "completed",
"paymentStatus": "paid",
"amountTotal": 49.99,
"currency": "USD",
"metadata": {
"local_checkout_session_id": "164",
"order_id": "42"
},
"transaction": {
"id": "txn_987654",
"originalTransactionId": "txn_987654",
"authAmount": 49.99
}
}
}
Event types
Checkout-related events handled by this demo app (suffix after rapidcents.):
checkout.session.created
Session opened at gateway
checkout.session.expired
Session timed out
checkout.session.cancelled
Shopper or merchant cancelled
payment.succeeded
Charge approved
payment.failed
Decline or error
payment.voided
Authorization voided
payment.refunded
Full refund
payment.partially_refunded
Partial refund
Payment events with sourceName other than checkout_session are ignored by this demo. Legacy suffixes such as checkout.payment.succeeded are normalized to payment.succeeded.
Inner payload fields
Use these fields to correlate a webhook with your local checkout session:
sourceName
Should be checkout_session for checkout integrations.
sourceId
Gateway checkout session UUID — primary correlation key.
sessionToken
Public session token (same as create/pay response token).
sessionStatus
Gateway session lifecycle: pending, completed, expired, cancelled, failed.
paymentStatus
Gateway payment state: unpaid, paid, failed, etc.
metadata.local_checkout_session_id
Optional id you sent at session create — fastest lookup in this app.
transaction.id
Charge / transaction id for void, refund, and reconciliation.
transaction.authAmount
Amount for refund webhooks (preferred over amountTotal).
isFinalFailure
On payment.failed, when true marks terminal failure.
Sample payloads
payment.succeeded
{
"sourceName": "checkout_session",
"sourceId": "550e8400-e29b-41d4-a716-446655440000",
"sessionToken": "cs_live_a1b2c3",
"sessionStatus": "completed",
"paymentStatus": "paid",
"amountTotal": 29.99,
"currency": "USD",
"metadata": { "local_checkout_session_id": "164" },
"transaction": {
"id": "txn_987654",
"originalTransactionId": "txn_987654",
"authAmount": 29.99
}
}
payment.voided
{
"sourceName": "checkout_session",
"sourceId": "550e8400-e29b-41d4-a716-446655440000",
"sessionToken": "cs_live_a1b2c3",
"sessionStatus": "cancelled",
"paymentStatus": "voided",
"transaction": {
"id": "txn_987654",
"originalTransactionId": "txn_987654"
}
}
payment.partially_refunded
{
"sourceName": "checkout_session",
"sourceId": "550e8400-e29b-41d4-a716-446655440000",
"sessionToken": "cs_live_a1b2c3",
"sessionStatus": "completed",
"paymentStatus": "partially_refunded",
"amountTotal": 29.99,
"transaction": {
"id": "txn_987654",
"originalTransactionId": "txn_987654",
"authAmount": 5.00
}
}
authAmount on the transaction object is the refunded amount for this event. Full refunds use payment.refunded with the same shape.
payment.failed
{
"sourceName": "checkout_session",
"sessionToken": "cs_live_a1b2c3",
"sessionStatus": "pending",
"paymentStatus": "failed",
"isFinalFailure": false
}
Void & refund
Void and refund are initiated through RapidCents transaction APIs (from your server or this app’s admin UI). Status changes are applied when the matching webhook arrives, not when the API returns.
- Void —
POST {API origin}/api/{business_id}/transactions/{transaction_id}/void→ awaitpayment.voided. - Refund —
POST {API origin}/api/{business_id}/transactions/{transaction_id}/refundwith amount → awaitpayment.refundedorpayment.partially_refunded.
Admin UI in this demo
Admin → Checkout sessions → Void / Refund submits the API call and shows a pending state until the webhook updates payment_status and refund history.
This demo app
- Entry point —
WebhookController→WebhookProcessingService. - Dedup —
payment_webhooks.event_idstoreswebhookId(fallbacknotificationId). - Lookup order —
metadata.local_checkout_session_id, storedgateway_source_id,external_session_id/ token. - Columns —
checkout_sessions.status(session lifecycle) andpayment_status(paid, voided, refunded, etc.) are synced from webhook payloads.
Handler checklist
1. Read raw body; verify HMAC when webhook_secret is configured.
2. Parse JSON envelope; dedupe by webhookId.
3. Branch on eventType (strip rapidcents. prefix).
4. Resolve local session using sourceId, sessionToken, metadata.
5. Update order / payment state idempotently.
6. Return 2xx quickly; log unmatched events for investigation.