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

Payment failure recovery example

Quick start

To implement the Failed Payment Wall:

  1. Ensure the Churnkey script is loaded
  2. Add the below code to your application initialization
  3. 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:

  1. Blocks access to your application
  2. Displays a payment update form
  3. Processes the new payment method
  4. Restores application access on success

Configuration

Core options

OptionTypeDefaultDescription
modestring'live''live' or 'test' environment
softWallbooleanfalseAllow customers to exit the wall
gracePeriodDaysnumber0Days to show dismissible wall before enforcing
forceCheckbooleanfalseBypass payment status cache
ignoreInvoicesWithoutAttemptbooleanfalseOnly 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:

EventDescription
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:

  1. Create a test customer
  2. Add the test card: 4000000000000341 (Stripe's "Decline After Attaching" card)
  3. Create and add a subscription item to an invoice
  4. Enable auto-charging for the invoice
  5. Finalize the invoice to trigger the failed payment
  6. Verify the Failed Payment Wall appears

Watch a complete walkthrough: