Easy Labs
BillingConcepts

Dunning config

The Dunning config entity in Billing.

The Dunning config is the per-merchant policy for what happens when a recurring charge fails: how many times to retry, on what schedule, what email to send, where to send the customer to fix it, and what terminal state to move the subscription or invoice into when retries are exhausted. There is exactly one config per merchant; it applies to every subscription and charge_automatically invoice.

Lifecycle

  1. Create or replace the config with createOrReplaceDunningConfig. New merchants start with no config and the engine falls back to safe defaults until one exists.
  2. Read the current policy with getDunningConfig.
  3. Patch individual fields with updateDunningConfig — useful for toggling email enablement or swapping a recovery page mode without re-stating the full schedule.
  4. The engine consults the config on every payment failure. It picks a retry slot from smart_retry_window (with smart_retry_attempts total) or steps through custom_retry_schedule. Bank-debit retries follow bank_debit_retry_schedule when bank_debit_retries_enabled is true.
  5. When retries are exhausted, the engine applies subscription_terminal_action to the subscription (cancel, unpaid, past_due, pause) and invoice_terminal_action to any open invoice (past_due, uncollectible). invoice.marked_uncollectible and subscription.updated events fire accordingly.

Relationships

The dunning config governs every Subscription and every Invoice collected with collection_method: "charge_automatically". Recovery emails link customers to either a hosted recovery page or a custom_link_url you supply (typically the Customer portal). For event-driven workflows beyond retries, layer revenue-recovery automations on top via createRevenueRecoveryAutomation — these are conditional rules that fire on triggers like invoice_overdue and subscription_payment_failed.

Fields that matter

  • retry_mode (smart | custom) — smart uses the platform-tuned schedule sized by smart_retry_window (1_week, 2_weeks, 3_weeks, 1_month, 2_months) and smart_retry_attempts (4 or 8); custom follows custom_retry_schedule (array of day offsets).
  • bank_debit_retries_enabled + bank_debit_retry_schedule — separate retry track for ACH/bank-debit failures, which have different reason codes and longer settlement windows than card declines.
  • subscription_terminal_action (cancel | unpaid | past_due | pause) — what state the subscription lands in after the final retry fails.
  • invoice_terminal_action (past_due | uncollectible) — what state the invoice lands in. uncollectible emits invoice.marked_uncollectible and stops further automated collection.
  • payment_failed_email_enabled / expiring_card_email_enabled / email_action_required — toggles for the three customer-facing email types the engine sends.
  • payment_failed_recovery_page_mode + payment_failed_custom_link_urlhosted directs to the white-label recovery page; custom_link deep-links to your own URL (e.g. a customer portal session).

On this page