Subscriptions
PerfectPay handles recurring billing through the subscriptions API, mandate management for saved payment authorization, and cross-processor retry logic that recovers failed charges by attempting them on alternate connectors.
Recurring Billing Setup
Create a subscription to bill a customer on a recurring schedule.
POST /subscriptions
curl https://sandbox.perfectpay.ai/subscriptions \
-X POST \
-H "api-key: YOUR_SECRET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_abc123",
"amount": 2999,
"currency": "USD",
"recurring_details": {
"type": "plan",
"interval": "monthly",
"start_date": "2026-04-01"
},
"payment_method_id": "pm_saved_card_001",
"description": "Pro Plan - Monthly"
}'
The subscription creates payment intents automatically at each billing cycle. Each generated payment follows your routing rules, so if your primary processor declines, the retry logic kicks in.
See the subscriptions API reference for the full field set.
Usage-Based and Metered Billing
For usage-based billing, report usage during the billing period and let PerfectPay calculate the charge at cycle end.
The pattern:
- Create a subscription with
"type": "metered"and a unit price - Report usage events throughout the billing period via the API
- At the billing cycle boundary, PerfectPay sums the reported usage and creates a payment for the calculated amount
curl https://sandbox.perfectpay.ai/subscriptions/{subscription_id}/usage \
-X POST \
-H "api-key: YOUR_SECRET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"quantity": 150,
"timestamp": "2026-03-15T14:30:00Z",
"action": "increment",
"metadata": {
"feature": "api_calls"
}
}'
Hybrid Billing Models
Combine a fixed base fee with usage-based charges for plans like "$29/month plus $0.01 per API call."
Configure hybrid billing by setting both a base amount and a metered component on the subscription:
{
"amount": 2900,
"recurring_details": {
"type": "hybrid",
"interval": "monthly",
"metered_component": {
"unit_amount": 1,
"unit_label": "api_call"
}
}
}
At each billing cycle, PerfectPay charges the base amount plus the accumulated metered usage.
Dunning and Retry Logic
When a recurring charge fails, PerfectPay does not give up after one attempt. The retry logic works at two levels:
Same-Connector Retry
If a charge fails with a soft decline (insufficient funds, temporary issuer error), PerfectPay retries on the same connector after a configurable delay.
Cross-Connector Retry
If the decline is hard or the connector is down, PerfectPay routes the retry to the next eligible connector in your routing configuration. This is where having multiple connectors pays off -- a decline on one processor does not mean the card is actually bad.
Retry Schedule
Configure the retry schedule per subscription or use the account-level default:
| Attempt | Timing | Behavior |
|---|---|---|
| 1 | Billing date | Primary connector |
| 2 | +1 day | Same connector, soft retry |
| 3 | +3 days | Next eligible connector |
| 4 | +7 days | Next eligible connector |
After all retries are exhausted, the subscription moves to past_due. You can configure whether to cancel automatically or hold for manual recovery.
Dunning Communication
Subscribe to these webhook events to trigger customer-facing dunning emails:
payment_failed-- charge attempt failed, retry scheduledsubscription_past_due-- all retries exhaustedsubscription_canceled-- subscription canceled after dunning period
See Events & Webhooks for webhook configuration.
Mandate Management
Mandates authorize PerfectPay to charge a saved payment method for recurring transactions. They are required for:
- Card-on-file -- storing a card and charging it later without the customer present
- Bank debit -- ACH, SEPA Direct Debit, and other pull-based bank methods
- Wallet recurring -- recurring charges through wallet providers that require pre-authorization
Create a mandate alongside the first payment:
curl https://sandbox.perfectpay.ai/payments \
-X POST \
-H "api-key: YOUR_SECRET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 2999,
"currency": "USD",
"customer_id": "cus_abc123",
"setup_future_usage": "off_session",
"mandate_data": {
"customer_acceptance": {
"acceptance_type": "online",
"online": {
"ip_address": "198.51.100.42",
"user_agent": "Mozilla/5.0..."
}
},
"mandate_type": {
"single_use": null,
"multi_use": {
"amount": 2999,
"currency": "USD"
}
}
},
"confirm": true,
"payment_method": "card",
"payment_method_type": "credit",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "12",
"card_exp_year": "27",
"card_cvc": "123",
"card_holder_name": "Jane Doe"
}
},
"return_url": "https://example.com/subscribe/complete"
}'
The mandate is linked to the saved payment method. Subsequent subscription charges reference the mandate automatically.
See the mandates guide for multi-use vs single-use mandates and bank debit specifics.
Plan Management
Manage subscription tiers through the API:
- Upgrade -- change the subscription amount and interval mid-cycle with prorated billing
- Downgrade -- schedule a plan change to take effect at the next billing cycle
- Pause -- suspend billing without canceling the subscription
- Cancel -- stop future charges, optionally at period end
curl https://sandbox.perfectpay.ai/subscriptions/{subscription_id} \
-X PUT \
-H "api-key: YOUR_SECRET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 4999,
"metadata": {
"plan": "enterprise",
"change_type": "upgrade",
"prorate": true
}
}'
Next Steps
- Subscriptions API -- full API reference for subscription operations
- Mandates -- mandate types, bank debit mandates, and compliance
- Smart Routing -- route subscription charges across multiple processors
- Events & Webhooks -- subscribe to subscription lifecycle events