Dunning profiles

Customize retry schedules and failure handling for different subscription types with dunning profiles.
View as Markdown

Overview

Dunning profiles let you customize payment recovery behavior beyond the default settings. Each profile defines:

  • Retry schedule: How many retries and how often
  • Failure handling: What happens when all retries fail
  • Email notifications: Which emails to send at each retry step

Profiles are applied at the start of a dunning cycle and remain locked for that cycle. Changes to a profile don’t affect in-flight dunning cycles.


System default profiles

Every account comes with four system default profiles optimized for different billing cycles:

ProfileTarget CycleMax RetriesRetry IntervalBest For
Daily - Quick RecoveryDaily323 hoursDaily subscriptions
Short Cycle - Standard Recovery2-6 days448 hoursWeekly subscriptions
Monthly - Standard Recovery7-30 days896 hoursMonthly subscriptions
Long Cycle - Extended Recovery30+ days1096 hoursAnnual subscriptions

System defaults cannot be modified or deleted, but you can clone them to create custom variations.


Custom profiles

Create custom profiles to tailor dunning behavior for specific use cases.

Create a profile

cURL
$curl -X POST https://api.paymentkit.com/v1/dunning/profiles \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Premium Customers",
> "description": "Extended recovery for high-value subscriptions",
> "max_retries": 12,
> "retry_interval_hours": 72,
> "termination_action": "leave_active",
> "invoice_status_on_failure": "leave_open",
> "enable_emails": true,
> "email_map": [
> {"retry_step": 0, "template": "payment_failed"},
> {"retry_step": 3, "template": "payment_reminder"},
> {"retry_step": -1, "template": "final_warning"}
> ]
> }'

Profile settings

FieldTypeDefaultDescription
namestringrequiredDisplay name (max 100 chars)
descriptionstringnullOptional description (max 500 chars)
max_retriesinteger8Number of retry attempts (1-15)
retry_interval_hoursinteger96Hours between retries (1-168)
termination_actionstring"cancel""cancel" or "leave_active"
invoice_status_on_failurestring"mark_uncollectible""mark_uncollectible" or "leave_open"
enable_emailsbooleantrueWhether to send dunning emails
email_maparray[]Email templates for specific retry steps

Email map

The email_map array controls which email templates are sent at each retry step:

1{
2 "email_map": [
3 {"retry_step": 0, "template": "payment_failed"}, // First retry
4 {"retry_step": 2, "template": "payment_reminder"}, // Third retry
5 {"retry_step": -1, "template": "final_warning"} // Final retry (special value)
6 ]
7}

Use retry_step: -1 to target the final retry, regardless of how many retries are configured.

Clone a profile

Create a copy of an existing profile (including system defaults):

cURL
$curl -X POST https://api.paymentkit.com/v1/dunning/profiles/{profile_id}/clone \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{"name": "My Custom Monthly Profile"}'

Archive a profile

Archiving soft-deletes a profile. Archived profiles don’t appear in the default list but remain accessible by ID. In-flight dunning cycles using the profile continue unaffected.

cURL
$curl -X DELETE https://api.paymentkit.com/v1/dunning/profiles/{profile_id} \
> -H "Authorization: Bearer sk_live_..."

Profile assignments

By default, PaymentKit selects a system default profile based on the subscription’s billing cycle. Use profile assignments to override this for specific prices or billing cycle categories.

Resolution order

When a dunning cycle starts, PaymentKit resolves the profile using a 2-tier priority:

  1. Price assignment — If the subscription’s price has a profile assigned, use that profile
  2. Cycle-length assignment — If no price assignment, check for a cycle_length category assignment
  3. System default — Fall back to the system default for the billing cycle type

Assign to a price

Target a specific product price for custom dunning behavior:

cURL
$curl -X POST https://api.paymentkit.com/v1/dunning/profiles/{profile_id}/assignments \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "resource_type": "price",
> "resource_id": "prc_live_abc123"
> }'

Assign to a cycle length

Target all subscriptions with a specific billing cycle category:

cURL
$curl -X POST https://api.paymentkit.com/v1/dunning/profiles/{profile_id}/assignments \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "resource_type": "cycle_length",
> "resource_id": "monthly"
> }'

Valid cycle lengths: daily, short, medium, long

Cycle LengthBilling Period
daily1 day
short2-6 days
medium7-30 days
long31+ days

List assignments

cURL
$curl https://api.paymentkit.com/v1/dunning/profiles/{profile_id}/assignments \
> -H "Authorization: Bearer sk_live_..."

Delete an assignment

cURL
$curl -X DELETE https://api.paymentkit.com/v1/dunning/profiles/{profile_id}/assignments/{assignment_id} \
> -H "Authorization: Bearer sk_live_..."

Profile snapshots

When a dunning cycle starts, PaymentKit captures a snapshot of the assigned profile’s settings. This snapshot is immutable for the duration of the dunning cycle.

Changes to a profile (including archiving) don’t affect dunning cycles already in progress. Each cycle uses its frozen snapshot.

This ensures predictable behavior:

  • Updating max_retries from 8 to 5 won’t suddenly cut short an in-progress cycle
  • Archiving a profile won’t disrupt active dunning cycles using it
  • New dunning cycles always get the latest profile settings

The snapshot is stored in the dunning state and includes all profile fields:

1{
2 "profile_snapshot": {
3 "profile_id": "dp_live_abc123",
4 "profile_name": "Premium Customers",
5 "max_retries": 12,
6 "retry_interval_hours": 72,
7 "termination_action": "leave_active",
8 "invoice_status_on_failure": "leave_open",
9 "enable_emails": true,
10 "email_map": [...]
11 }
12}

Best practices

Start with system defaults

System defaults are optimized for common billing cycles. Clone them as a starting point for custom profiles.

Use price assignments for exceptions

Assign profiles to specific prices (e.g., annual enterprise plans) rather than creating many cycle-length assignments.

Test with short retry intervals

When testing, create a profile with retry_interval_hours: 1 to see the full dunning cycle quickly.

Don't over-customize

Most merchants need 1-3 profiles. Complex assignment hierarchies are harder to reason about.