Stripe Subscription Status
Query subscription status, past-due state, and cancellation schedule from Stripe API
Instructions
Stripe Subscription Status
Prerequisites
- Stripe account with API access (secret key)
- Active subscriptions to query
Query a Single Subscription
curl https://api.stripe.com/v1/subscriptions/sub_XXXXX \
-u sk_live_YOUR_KEY:
Key fields for payment failure recovery:
status:active,past_due,unpaid,canceled,incomplete,incomplete_expired,trialing,pausedlatest_invoice: the most recent invoice object (expand for payment details)cancel_at_period_end: boolean, whether auto-cancel is scheduledcancel_at: timestamp when the subscription will cancel (if scheduled)days_until_due: number of days to pay after invoice creationdefault_payment_method: the payment method on file
List All Past-Due Subscriptions
curl "https://api.stripe.com/v1/subscriptions?status=past_due&limit=100" \
-u sk_live_YOUR_KEY:
This returns all subscriptions where the most recent invoice payment failed and Stripe is still retrying. These are your active recovery targets.
Expand Invoice and Payment Details
To get full failure context in a single API call:
curl "https://api.stripe.com/v1/subscriptions/sub_XXXXX?expand[]=latest_invoice.payment_intent&expand[]=default_payment_method" \
-u sk_live_YOUR_KEY:
This returns the subscription with its latest invoice, the payment intent (including failure reason), and the payment method details (card brand, last 4, expiry).
Subscription Lifecycle for Payment Failures
- Invoice created -> payment attempted ->
charge.failedevent - Subscription moves to
past_duestatus - Stripe retries per retry schedule (Smart Retries or custom)
- If all retries fail:
- If configured: subscription moves to
unpaid(access revoked, can be reactivated) - If configured: subscription moves to
canceled(permanent) - Default: stays
past_dueuntil manual intervention
- If configured: subscription moves to
Batch Query: Subscriptions At Risk
Query all subscriptions that are past due or have upcoming payment that is likely to fail (card expiring soon):
// Past-due subscriptions (payment already failed)
const pastDue = await stripe.subscriptions.list({
status: 'past_due',
limit: 100,
expand: ['data.latest_invoice', 'data.default_payment_method']
});
// Subscriptions with expiring cards (proactive prevention)
const expiringSoon = await stripe.paymentMethods.list({
type: 'card',
limit: 100
});
const atRisk = expiringSoon.data.filter(pm => {
const expiryDate = new Date(pm.card.exp_year, pm.card.exp_month - 1);
const daysUntilExpiry = (expiryDate - new Date()) / (1000 * 60 * 60 * 24);
return daysUntilExpiry > 0 && daysUntilExpiry <= 30;
});
Error Handling
resource_missing: subscription does not exist (may have been deleted)rate_limit: Stripe allows 100 reads/sec in live mode; use pagination for large lists- Expand requests count against rate limits more heavily; batch queries should paginate at 100/page
Alternative Tools
| Tool | Status Query | Documentation |
|------|-------------|---------------|
| Stripe | GET /v1/subscriptions | stripe.com/docs/api/subscriptions |
| Paddle | GET /subscriptions | developer.paddle.com |
| Chargebee | GET /subscriptions | apidocs.chargebee.com |
| Recurly | GET /subscriptions | docs.recurly.com |
| Braintree | Subscription search API | developer.paypal.com/braintree |