SubscriptionResponseDto
Example
{ "id": "string", "account_id": "string", "plan_code": "free", "status": "trialing", "billing_cycle": "monthly", "current_period_start": "2026-04-20T12:00:00.000Z", "current_period_end": "2026-04-20T12:00:00.000Z", "cancel_at_period_end": false, "scheduled_plan_code": "starter", "promotion_code": "string", "discount": { "code": "string", "amount_off": 0, "percent_off": 0, "currency": "string", "ends_at": "2026-04-20T12:00:00.000Z" }, "trial_started_at": "2026-04-20T12:00:00.000Z", "trial_ends_at": "2026-04-20T12:00:00.000Z", "last_payment_attempt_at": "2026-04-20T12:00:00.000Z", "grace_ends_at": "2026-04-20T12:00:00.000Z", "payment_retry_count": 0, "unit_amount": 0, "currency": "string", "interval": "string" }
Properties
Lifecycle state. `active` is the happy path; `past_due` and `cancelled` should surface a banner / disable upgrade affordances in the dashboard.
Start of the current billing period (UTC ISO timestamp). `null` for Free / outside any active Stripe period.
End of the current billing period (UTC ISO timestamp). When `cancel_at_period_end=true`, the dashboard shows this as the cancel date; otherwise it's the next renewal date.
True when the subscription is scheduled to cancel at `current_period_end`. Stripe webhook flips `status` to `cancelled` when the period closes.
The lower paid plan the subscription moves to at `current_period_end`, or null. Undone with `DELETE /billing/scheduled-downgrade`.
The promotion code the subscription was started with, kept after its discount ends.
When the current trial ends (UTC ISO). Dashboard surfaces a countdown for trialing subscriptions in later slices.
Timestamp of the most recent payment attempt (success or failure), synced from Stripe webhooks.
When paid features are revoked if the failed payment is not settled (UTC ISO), counted from when the subscription went past due. Null unless it is past due.
Count of consecutive failed payment attempts on the current open invoice. Resets to 0 on a successful charge. Renders the `N of 4 attempts` copy in the dunning banner.
What this Account is charged per billing period, in the smallest currency unit, read from its own Stripe subscription. Null for Free, and for any subscription with no priced item. Per-account rather than per-plan because Enterprise customers are contracted individually against custom Stripe products — their negotiated amount exists only on their subscription, so a shared price table could only ever show them someone else's price.
Tell us how we can improve this guide.