subbydocs
Visit Subby Start building

Subscription lifecycle

How Subby's subscription engine moves a subscription through statuses, renewals, failed-charge retries, nudges, escalation and cancellation.

A subscription connects a customer to a plan. Subby's subscription engine renews it on schedule. If a charge fails, the engine retries, reminds the customer and, if the customer still does not pay, takes the escalation action you chose on the plan.

Subby is not a payment engine. The payment rail attempts each charge. The subscription engine owns status, retries, nudges and what happens next.

Statuses

Status Meaning Should the customer have access?
incomplete Created, waiting for the first payment or for checkout to finish No
trialing In a free trial. No charge until trial_end Yes
active Paid and in good standing Yes
past_due A renewal payment failed and Subby is retrying Your choice. Most platforms keep access during retries
paused Billing is paused, either by you, by the customer, or by the pause_service escalation No
cancelled Ended. Terminal, won't be charged again No
                 checkout completes
  incomplete ───────────────────────▶ trialing ──trial ends, paid──▶ active
      │                                                               │  ▲
      │ first payment fails / expires                   renewal fails │  │ retry succeeds
      ▼                                                               ▼  │
  cancelled ◀── unpaid too long ── paused ◀── escalation ── past_due ───┘
      ▲                               │
      └──────── cancel ───────────────┘ resume ──▶ active

Renewals

At the end of each period Subby creates a charge for the plan amount (plus any usage-based overage_per_unit you reported) and tries the customer's default payment method.

  • Success: the period advances, current_period_end moves forward, and you receive charge.succeeded and subscription.renewed.
  • Failure: the subscription moves to past_due, you receive charge.failed and subscription.past_due, and the retry schedule starts.

Retries

Each plan has a retry_logic object:

{
  "enabled": true,
  "max_attempts": 3,
  "retry_intervals_days": [1, 3, 7],
  "escalation_on_failure": "pause_service",
  "cancel_after_days_unpaid": 30
}

With this setup, if a renewal fails on 1 October, Subby retries on 2, 4 and 8 October. Each retry creates a new charge with an increasing attempt_number, and sends charge.retry_scheduled before the next attempt.

Subby skips the remaining retries when the failure code isn't retryable, like expired_card. Instead it moves straight to asking the customer for a new payment method. See payment failure codes.

Automatic retries are free. They are not API requests and are never metered.

Nudges

A nudge is one reminder delivered to one customer on one channel. The plan's reminders object controls automatic nudges:

{
  "enabled": true,
  "channels": ["whatsapp", "sms", "email"],
  "pre_due_days": [3],
  "post_due_days": [1, 3, 7]
}
  • pre_due_days sends a reminder before a renewal is due.
  • post_due_days sends a reminder after a payment has failed.
  • channels is in order of preference. Subby tries the first channel the customer has contact details for, and falls back to the next if delivery fails.

Every nudge message includes a secure link where the customer can pay or update their payment method.

A nudge counts toward your nudge allowance when it is delivered or sent without a delivery receipt. Nudges that fail before sending (for example, no phone number) don't count. You receive nudge.sent, and then nudge.delivered or nudge.failed.

You can also send a nudge yourself with POST /nudges. That's 1 write request plus 1 nudge.

Escalation

When the last retry fails, Subby takes the plan's escalation_on_failure action and sends subscription.escalated:

Value What Subby does What you should do
pause_service Sets the subscription to paused and sends subscription.paused Remove access until the customer pays
restrict_access Keeps the subscription past_due and sends subscription.escalated with action: "restrict" Limit access, such as read-only mode
hold_delivery Keeps the subscription past_due and sends subscription.escalated with action: "hold" Stop physical deliveries or service visits
none Keeps the subscription past_due. No action Decide yourself

If the customer pays through a nudge link at any point, Subby charges them, sets the subscription back to active, and sends charge.succeeded and subscription.recovered.

If the customer is still unpaid cancel_after_days_unpaid days after the first failure, Subby cancels the subscription with cancellation_reason: "nonpayment" and sends subscription.cancelled. Set cancel_after_days_unpaid to null to never cancel automatically.

Pausing and resuming

If a plan has pause_enabled: true, you can pause a subscription:

curl -X POST "https://api.mysubbyapp.com/v1/subscriptions/sub_9fK3mQ2xLp/pause" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "resumes_at": "2026-11-01T00:00:00Z", "reason": "customer_travelling" }'
  • No charges or reminders happen while paused.
  • Leave out resumes_at to pause until you call POST /subscriptions/{id}/resume.
  • On resume, the new period starts on the resume date. With pro_rate: true on the plan, the first charge is prorated.

Cancelling

curl -X POST "https://api.mysubbyapp.com/v1/subscriptions/sub_9fK3mQ2xLp/cancel" \
  -H "Authorization: Bearer $SUBBY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "at_period_end": true, "reason": "customer_request" }'
  • at_period_end: true keeps the subscription active until current_period_end, sets cancel_at_period_end: true, then cancels. You can undo this with PATCH /subscriptions/{id} and "cancel_at_period_end": false.
  • at_period_end: false cancels immediately.

Events by stage

Stage Events
Created subscription.created
Trial ending in 3 days subscription.trial_will_end
Paid charge.succeeded, subscription.renewed
Payment failed charge.failed, subscription.past_due, charge.retry_scheduled
Reminder sent nudge.sent, nudge.delivered or nudge.failed
Recovered charge.succeeded, subscription.recovered
Escalated subscription.escalated, and subscription.paused for pause_service
Paused / resumed subscription.paused, subscription.resumed
Updated subscription.updated
Cancelled subscription.cancelled

See the full event catalogue.

Frequently asked questions

What does the subscription engine do after a charge fails?

It retries on the plan schedule, sends configured nudges, and applies the plan's escalation action if the subscriber still does not pay.

Does a failed charge mean Subby is the payment engine?

No. The payment rail attempts the charge. The subscription engine updates status, recovery and access rules around that result.