Skip to main content
Revtain sends webhook notifications to the URL you registered during onboarding when a recovery attempt reaches a final state. Every webhook is signed for verification.

Webhook Security

Every outbound webhook includes an X-Revtain-Signature header containing an HMAC-SHA256 signature computed using your webhookSigningSecret.
Always verify signatures before processing webhook events. Unsigned or invalid requests should return 401 Unauthorized.

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.
Action: Mark the customer’s invoice as paid in your billing system.
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.
Action: Branch on 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.
Action: Branch on 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.
Action: Consider reaching out to the customer to update their payment method before the next billing cycle. Generate a card update link via /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.
This event is additive — older integrations that don’t handle it can safely ignore it. The same skip also fires Revtain’s normal dunning hooks, so you don’t need to wire recovery.skipped_high_risk unless you want richer telemetry on why a particular charge was skipped.

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.
Action: run your standard failed-payment process for this payment — exactly what you did before Revtain. If your integration doesn’t handle this event, nothing breaks: the synchronous API response for held-out requests reports 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.
Action: Reach out to the customer and ask them to update their card before the next renewal.
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 receive card.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:
Action: forward 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.
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.
Action: Re-attempt the charge through your own checkout with 3-D Secure enabled, so the customer can authenticate.

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.
Action: Generate a card update link (or use the one from a related event) and send it to the customer through your own channel. Delivery of this event is durable — a brief outage on your side will not lose it.

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.
Action: Bring the customer back through your own checkout with authentication enabled, then re-attempt the charge from your side.

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.
Action: Apply the customer’s decision in your billing system — pause, downgrade, or cancel the subscription, or take no action if they were retained.