Failed Payment Recovery
Failed Payment Wall
Block access to your application when payments fail
The Failed Payment Wall helps you recover revenue by automatically blocking access to your application when a customer's payment fails. It displays a streamlined UI for customers to update their payment information and immediately retry failed charges.

Currently available for Stripe only
Quick start
To implement the Failed Payment Wall:
- Ensure the Churnkey script is loaded
- Add the below code to your application initialization
- Customize the wall behavior (optional)
window.churnkey.check('failed-payment', {
// Required - Authentication & identification
customerId: 'CUSTOMER_ID',
authHash: 'HMAC_HASH',
appId: 'YOUR_APP_ID',
provider: 'stripe',
// Optional - Wall behavior
mode: 'live', // Use 'test' for development
softWall: false, // Allow users to exit the wall
gracePeriodDays: 0, // Days before enforcing hard wall
forceCheck: false // Skip caching (not recommended)
})
How it works
The Failed Payment Wall activates automatically when:
- A customer has invoices with
open
status in the last 60 days - Their most recent invoice is not
paid
When activated, it:
- Blocks access to your application
- Displays a payment update form
- Processes the new payment method
- Restores application access on success
Configuration
Core options
Option | Type | Default | Description |
---|---|---|---|
mode | string | 'live' | 'live' or 'test' environment |
softWall | boolean | false | Allow customers to exit the wall |
gracePeriodDays | number | 0 | Days to show dismissible wall before enforcing |
forceCheck | boolean | false | Bypass payment status cache |
ignoreInvoicesWithoutAttempt | boolean | false | Only show wall for failed charge attempts |
Custom display logic
Control when to show the wall based on your business rules:
window.churnkey.check('failed-payment', {
// ... other options
shouldShowFailedPaymentWall(overdueInvoice, customer) {
// Examples:
if (overdueInvoice.amountDue > 50000) {
return false // Skip for high-value invoices
}
if (customer.isVIP) {
return 'soft' // Allow VIPs to dismiss
}
return true // Show wall for others
}
})
Return values:
true
- Show wall (follows softWall setting)false
- Don't show wall'soft'
- Show dismissible wall'hard'
- Show enforced wall
Optional UI elements
Add extra buttons to the wall:
window.churnkey.check('failed-payment', {
// ... other options
handleLogout() { }, // Add logout button
handleSupportRequest() { }, // Add support button
handleCancel() { } // Add cancel subscription button
})
Event callbacks
Monitor wall activity:
Event | Description |
---|---|
onFailedPaymentWallActivated() | Wall is displayed |
onUpdatePaymentInformation(customer) | Payment updated successfully |
onFailedPaymentWallClose() | Wall is dismissed (soft wall only) |
onError(error, type) | Error occurred |
Error types:
FAILED_PAYMENT_WALL_INITIALIZATION_ERROR
FAILED_PAYMENT_WALL_UPDATE_CARD_ERROR
FAILED_PAYMENT_WALL_CANCEL_ERROR
Testing
Test the implementation using Stripe's test cards:
- Create a test customer
- Add the test card:
4000000000000341
(Stripe's "Decline After Attaching" card) - Create and add a subscription item to an invoice
- Enable auto-charging for the invoice
- Finalize the invoice to trigger the failed payment
- Verify the Failed Payment Wall appears
Watch a complete walkthrough: