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)
  subscriptionId: 'SUBSCRIPTION_ID' // Target specific subscription
})
How it works
The Failed Payment Wall activates automatically when:
- A customer has invoices with openstatus 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: