Webhook Security
Every outbound webhook includes anX-Revtain-Signature header containing an HMAC-SHA256 signature computed using your webhookSigningSecret.
Step-by-Step Verification
1
Set up your webhook endpoint
HTTPS endpoint that accepts POST with JSON body and returns
200 OK.2
Store your webhook signing secret
Save
webhookSigningSecret securely. This is different from your API key.3
Verify every incoming request
Compute HMAC-SHA256 using your secret, compare with
X-Revtain-Signature.4
Process the event and respond 200
Always respond within 10 seconds. Slow endpoints trigger retries.
Code Examples
Always respond with
200 within 10 seconds. If your endpoint is down or slow, Revtain retries delivery automatically — three immediate attempts (0s, 2s, 8s), then, if those fail, a durable retry schedule over the following 24 hours. A brief outage on your side will not lose an event.Event Reference
recovery.success
Sent when a previously failed payment has been successfully recovered.
Correlating a webhook back to your invoice. When you call
/api/recovery/execute, the response includes a transactionId. Store it against your invoice. The webhook’s revtainTransactionId is the same value — match on it to know which invoice this outcome belongs to. If you prefer to drive everything from your own key, pass an idempotencyKey (your invoice ID) on /execute and poll GET /api/recovery/status?idempotencyKey=... instead of waiting on the webhook.recovery.success and recovery.failed may carry an optional trigger field identifying what produced the outcome — for example a scheduled retry, or "reconciliation" when Revtain’s automatic reconciliation resolved a payment whose original gateway response was lost in transit. Handle both events the same way regardless of trigger; the field exists for your telemetry.recovery.failed
Sent when all retry strategies have been exhausted.
recommendedAction (see table below) and run your own customer outreach from your domain — see the dunning guide. Revtain never emails or messages your customers directly.
recommendedAction values
recovery.failed and recovery.blocked both carry a recommendedAction field, so your dunning logic can branch on a stable signal instead of parsing raw decline codes. recommendedActionReason is a human-readable explanation of the same signal.
recovery.blocked
Sent when a transaction is stopped before any retry — by the Risk Engine (fraud, lost card), because the issuer requires the customer to authenticate, or because the card was reported no longer chargeable (removed or replaced at the gateway; declineCode: card_no_longer_chargeable). In every case recommendedAction tells you the right next move.
recommendedAction. A manual_review value means flag the account and do not retry. A request_card_update value — for example when declineCode is authentication_required — means route the customer through your checkout to re-confirm their card.
card.updated
Sent when a customer updates their payment method via a hosted card update link.
Action: Store
newPaymentMethodToken and paymentMethodType against the customer record in your system. Use them on all future POST /api/recovery/execute calls for this customer. The old token is no longer valid for recovery — discard it.
newPaymentMethodToken is a gateway-native token (for example a Stripe pm_xxx or a Checkout.com src_xxx), issued by the same gateway that holds the customer’s account. You can pass it to your gateway directly as well — it’s a real gateway token, not a Revtain reference.predict.risk.high
Sent when the pre-failure risk prediction engine detects a high-risk payment before it fails. Enables proactive intervention.
/api/recovery/update-card/generate.
recovery.skipped_high_risk
Sent when the predictor scored the failure so low that attempting recovery would burn issuer velocity budget without a realistic chance of success. Revtain skips the retry entirely and surfaces a pre-generated card update link so you can route the customer straight to re-entering payment details.
Action: Send the
cardUpdateUrl to the customer via your existing channel (email, in-app message). Treating a skip as “the recovery failed” lets you maintain a clean state machine in your dunning logic.
recovery.holdout
Sent only on accounts running Proof Mode. The request landed in the measurement control group: Revtain made no recovery attempt and will not make one.
success: false, so your existing failure path already does the right thing.
recovery.proactive_retention
Sent when Revtain detects that a single customer has hit multiple recovery failures in a short window — a strong signal they’re at risk of churning. The event carries a pre-generated cancel-flow URL you can offer the customer to retain them with a pause, discount, or downgrade option before they actively cancel.
Action: Send
cancelFlowUrl to the customer via your existing channel. Customers who reach this link voluntarily are dramatically more likely to retain (via pause / downgrade) than customers who are forced through the dunning gauntlet first. Requires the cancel-flow feature to be enabled on your account.
recovery.proactive_retention is only fired for clients with the cancel-flow feature enabled. If you don’t use cancel flow today, this event never fires — you can safely ignore it.card.expiring_soon
Sent ahead of a renewal when the customer’s card on file is close to its expiry date, so you can prompt the customer before the payment fails. Fired by the pre-renewal card health check.
Field names vary by source: events from Revtain’s own sweeps use
expiryMonth/expiryYear, while events triggered by your billing platform’s upcoming-invoice notification use expMonth/expYear and may include daysUntilExpiry and upcomingInvoiceAmount. Handle both spellings, and treat any additional fields as optional and forward-compatible.Pre-emptive variant (card health sweep)
Accounts with the card health sweep enabled also receivecard.expiring_soon from Revtain’s own monitoring — a routine background check of active cards, independent of any billing platform. This variant is marked preemptive: true and includes a ready-made card-update link:
cardUpdateUrl to the customer through your own channel. The link stays valid for 14 days. Updating the card before the renewal means the decline never happens — the cheapest recovery there is.
recovery.3ds_recommended
Sent after a failed recovery when the decline pattern suggests the charge would clear with 3-D Secure authentication — typically a soft decline from a European or UK issuer.
recovery.card_expired
Sent when Revtain confirms a stored card is expired and cannot be recovered automatically — either at retry time, or after the card failed to refresh through the network’s automatic updater window. This is your cue to collect a new card.
recovery.authentication_required
Sent when a recovery attempt was declined because the issuer insists the customer authenticates (3-D Secure / SCA), and the compliant merchant-initiated path could not clear it. Only the customer can resolve this one.
churn.flow.{outcome}
Sent when a customer completes the hosted cancel flow. The event name carries the outcome: churn.flow.retained, churn.flow.paused, churn.flow.downgraded, or churn.flow.cancelled.