Skip to content

Subscriptions

A full subscription system with trials, seats, metered usage, proration, coupons, dunning and a customer portal, charged on your own processor account.

A subscription bills a customer for one or more recurring prices of a brand. Ownrecord runs the whole lifecycle: trials, renewals, plan changes, failed payments, pauses and cancellations. It's the same system Ownrecord uses to sell its own plans.

What it covers

  • Prices: flat, per seat, metered or tiered, and several items with different intervals in one subscription.
  • Trials, with or without a payment method up front.
  • Plan and quantity changes with proration, now or at the end of the period.
  • Coupons and promotion codes.
  • Included credits: a price can put credits into the customer's wallet every period.
  • Collection: charge a saved card automatically, or send an invoice to be paid by bank transfer.
  • Dunning: retries and reminders when a renewal payment fails (see collection and dunning).
  • Pause, resume and cancel, now or at the end of the period.
  • Entitlements, so your product knows what each customer may use.
  • A customer portal where customers manage their own subscriptions, payment methods and invoices.

Every renewal is quoted by the tax engine on its own tax point, and every invoice is issued in your entity's name and numbering.

Lifecycle

Text
create → incomplete ──(paid within 23 h)──→ active or trialing
                    └──(not paid)──→ incomplete_expired
create → trialing ──(trial ends, payment succeeds or nothing is due)──→ active
                  └──(trial ends, no payment method)──→ canceled or paused
active ──(renewal payment fails)──→ past_due ──(payment succeeds)──→ active
                                             └──(retries exhausted)──→ unpaid or canceled
active ──(pause)──→ paused ──(resume)──→ active
any state that isn't final ──(cancel now)──→ canceled
active ──(cancel at period end)──→ stays active until the period ends ──→ canceled
StatusMeaning
incompleteWaiting for the first payment, or for the customer to save a payment method.
incomplete_expiredThe first payment wasn't completed within 23 hours.
trialingIn a trial.
activePaid and running.
past_dueA renewal payment failed and retries are running.
unpaidRetries are exhausted. No new invoices and no entitlements; paying the open invoice reactivates it.
pausedCollection is stopped until it resumes, by hand or on a set date.
canceledEnded. A subscription set to cancel at period end can be reactivated before then.

What happens when a trial ends without a payment method, and when retries are exhausted, is set by each brand.

Every change of status is recorded as a subscription event and sent to your webhooks, so your product can react.

Creating a subscription

Subscribe an existing customer with the API, or let customers subscribe themselves through checkout.

HTTP
POST /api/v1/subscriptions
Idempotency-Key: 2b7e…

{
  "customerId": "cus_01m4…",
  "items": [{ "priceId": "price_01m4…", "quantity": 5 }],
  "collectionMethod": "charge_automatically",
  "trialDays": 14,
  "promotionCode": "LAUNCH20"
}
  • Items: up to 20 recurring prices of one currency. Their intervals must be whole multiples of each other, such as monthly and yearly. Licensed prices take a quantity (seats); metered prices bill what is used.
  • Collection: charge_automatically charges the customer's default payment method, or the one in paymentMethodId. send_invoice emails each invoice with your bank details, due daysUntilDue days after its issue date (14 by default), and needs no payment method.
  • Trial: trialDays or trialEnd. Without either, the prices' own trial applies. trialEndBehavior says what happens if the trial ends without a payment method: convert (bill anyway: the invoice stays open and the subscription goes past_due, see dunning), cancel_if_no_payment_method or pause_if_no_payment_method.
  • Billing cycle anchor: by default the first period starts now, or when the trial ends. A later billingCycleAnchor starts the cycle on that date. With prorationBehavior: create_prorations or always_invoice, the partial first period is billed now. With none, nothing is billed until the anchor.
  • Discounts: a couponId or a customer-facing promotionCode. See discounts.

What happens next depends on what is due:

SituationResult
A free plan: every licensed price is zero, nothing meteredactive, with no invoices.
A trialtrialing. The first invoice comes when the trial ends.
send_invoiceactive. The first invoice is finalized and emailed now.
charge_automatically with a payment methodincomplete until the first invoice is paid, then active. The charge runs right after the subscription is saved; the processor's webhook records the payment.
charge_automatically without a payment methodincomplete. The answer has paymentSetup.url: a checkout page in setup mode where the customer saves a card. The first invoice is charged as soon as the card is saved.

An incomplete subscription that isn't paid within 23 hours becomes incomplete_expired. A plan of zero-priced licensed items with a metered item still needs a payment method, because usage will be billed.

The first invoice is a real invoice: numbered in the brand's series, with tax quoted on its tax point. An invoice that adds up to zero, such as a fully discounted first period, isn't issued at all; the history says it was skipped.

Subscribing through checkout

A checkout session in subscription mode sells recurring prices on the hosted page:

HTTP
POST /api/v1/checkout/sessions

{
  "mode": "subscription",
  "lineItems": [{ "lookupKey": "pro_monthly", "quantity": 1, "adjustableQuantity": { "min": 1, "max": 50 } }],
  "allowPromotionCodes": true,
  "subscriptionData": { "trialDays": 14 },
  "successUrl": "https://app.example/welcome"
}
  • Without a trial, the customer pays the first invoice on the page. The card is saved for renewals at the same time.
  • With a trial, nothing is charged today: the page saves the card and shows when the trial ends. With subscriptionData.trialRequiresPaymentMethod: false, the trial starts without a card.
  • adjustableQuantity lets the customer choose the number of seats. allowPromotionCodes adds a promotion code field.
  • The page quotes the tax on the first paid invoice and shows what is due today.

The subscription is created when the processor confirms the payment or the saved card, never earlier. A session in setup mode has no line items: it only saves a card for a customer. That's the page that paymentSetup.url points to.

Changing a subscription

PATCH /api/v1/subscriptions/{id} changes the items: swap a price ({ id, priceId }), change seats ({ id, quantity }), add an item ({ priceId, quantity }) or remove one ({ id, deleted: true }). Items you don't name stay as they are. Send the version you read as expectedVersion, so two people changing the same subscription can't overwrite each other.

By default, an upgrade or a change of billing interval applies now: the unused time of the old items is credited and the new items are charged for the rest of the period, on an invoice issued and charged at once (always_invoice). A downgrade waits for the end of the period: it's stored as pendingUpdate and applied at the renewal.

Override the defaults with effective (now or period_end) and prorationBehavior:

  • always_invoice invoices the difference now;
  • create_prorations adds the difference to the next invoice; when the change lowers the price, the unused time goes to the customer's credit balance instead;
  • none changes the items without billing the difference.

If the charge for an upgrade fails, the change still applies and the invoice stays open for collection, which retries it. With paymentBehavior: pending_if_incomplete, the old items stay until the invoice is paid instead.

Preview first. POST /api/v1/subscriptions/{id}/preview_change takes the same changes and answers with exactly what would happen: when it applies, how it's settled, the invoice with its lines and tax, any credit, and the monthly recurring revenue before and after. It runs the change and rolls it back, so the invoice in the preview is the invoice the change issues, apart from its number. The console shows this preview before you confirm a plan change.

Credits for unused time go to the customer's credit balance, at the prices' amounts before tax, and reduce the next invoices.

Pause, cancel and reactivate

  • Pause (POST /api/v1/subscriptions/{id}/pause): renewals stop collecting. behavior says what happens to their invoices: void (none are issued; the default), keep_as_draft or mark_uncollectible. Give resumesAt to resume automatically, or resume by hand with /resume.
  • Cancel (POST /api/v1/subscriptions/{id}/cancel): mode: at_period_end (the default) keeps the subscription running until the period ends; until then /reactivate undoes it. mode: now ends it at once: usage so far and pending items go on a final invoice, and prorate: true credits the unused time to the credit balance. refund: true refunds the unused time to the customer's card instead, with a credit note for every paid invoice with time left (it needs the refund permission; an invoice paid by bank transfer or from the credit balance can't be refunded that way: subscription_refund_not_supported).
  • Store why the customer left with feedback (such as too_expensive) and an optional comment.

Customers can do much of this themselves in the customer portal, as your portal settings allow: switch plan along your plan-change matrix after seeing the price, change the quantity, apply a promotion code, choose the card, cancel (recorded with cancellation.by: "customer" and their reason) and keep a subscription they canceled. They get an email when a subscription renews, is set to end and ends (not after unsuccessful dunning, which dunning's own emails cover).

Metered items

A metered item bills a customer's usage of its meter. A customer can have at most one live metered item per meter, across all their subscriptions, because the usage of a meter is billed once per customer. Adding a second one is refused with subscription_meter_conflict. Usage events can name the item they belong to with subscriptionItemId, or leave it out.

Usage is billed in arrears: the renewal invoice at the end of a period bills that period's usage, with the price's included quantity, tiers, minimum and maximum applied to the whole period. Usage that arrives after its period was invoiced (a late event) is billed on the next invoice as its own "Late usage" line, the difference between what the period cost with and without it. If a period's usage turns negative (refunds reducing a volume, for example), its line is zero and the amount goes to the customer's credit balance.

Usage thresholds. For usage-heavy customers, set usageThreshold on the subscription (POST or PATCH, an amount in the subscription's currency). Once the usage not yet invoiced would cost at least that much, it's invoiced and charged at once instead of waiting for the period end. The period's renewal then bills only what the period's usage costs beyond that, so tiers and minimums still apply to the whole period.

Renewals

At the end of each period the subscription renews:

  1. An hour before the period ends, the renewal invoice is created as a draft, so you can see it and add invoice items to it.
  2. At the end of the period its lines are computed again and it's finalized: licensed items for the new period (in advance), metered usage of the period that ended (in arrears), late usage, pending items such as prorations, then discounts, a fresh tax quote and the customer's credit balance. It's charged to the saved payment method, or sent for send_invoice subscriptions, and the subscription moves to its next period (subscription.renewed).

A change scheduled for the end of the period (a downgrade, or a price change) applies at the renewal, and the new period is billed at the new price. A subscription set to cancel at the end of its period gets a final invoice of its usage and pending items instead, and ends. A trial's end works the same way, with the first invoice. A paused subscription renews by its pause behavior: no invoice (void), a draft that stays a draft (keep_as_draft), or an invoice written off at once (mark_uncollectible). An unpaid subscription issues no new invoices. With items of different intervals, each item is billed when its own period ends.

Included credits. A price with includedCredits grants them into the customer's wallet in the same step: at the start (or when a trial ends) and at every renewal while the subscription is active or past due, once per item and period. Paused and unpaid periods, trials and previews get none.

The upcoming invoice. GET /api/v1/invoices/upcoming?subscriptionId=sub_… shows the invoice the next renewal will issue, as it would be issued now: it runs the renewal and rolls it back, so it has every line, the tax and the amount due, but no number. Seven days before a renewal, the same preview goes to your webhooks as invoice.upcoming.

Revenue recognition. What a renewal bills in advance is booked as deferred revenue and recognised day by day over the period it pays for, to the second, once the invoice is paid (or written off). The ledger shows it moving from deferred_revenue to the product's revenue account.

Price changes for existing subscribers

Prices can't change once they are used, so to change what existing subscribers pay, create a new price and migrate them to it:

HTTP
POST /api/v1/subscriptions/migrations
Ownrecord-Dry-Run: true

{ "fromPriceId": "price_01m4…", "toPriceId": "price_01m9…", "noticeDays": 30 }

The two prices must bill alike (currency, interval, and usage type). Every subscription on the old price gets a change scheduled for its first renewal at least noticeDays away (or on or after effectiveDate, with effective: "date"). Each customer is emailed a notice noticeDays before their change, and the renewal applies it. Narrow the subscriptions with filter (statuses and customers); those with another change already scheduled, or set to cancel, are skipped.

Send it as a dry run first: the answer shows how many subscriptions it would change and the monthly recurring revenue before and after, without changing anything. GET /api/v1/subscriptions/migrations/{id} then reports progress: scheduled, notified, applied, pending and skipped. A migration changes what customers pay, so it's a financial action: approval policies can require an approval for agents.

History, webhooks and metrics

Every change writes a subscription event: created, trial started, upgraded, downgraded, quantity changed, discount applied, paused, resumed, cancellation scheduled, reactivated, canceled and more, each with the state before and after, who made it, and how it moved monthly recurring revenue (MRR). List them with GET /api/v1/subscriptions/{id}/events; the console shows them as the subscription's history.

Webhooks receive subscription.created, subscription.updated, subscription.paused, subscription.resumed, subscription.cancel_scheduled, subscription.canceled, and subscription.trial_will_end three days before a trial ends. Renewals and collection send subscription.renewed, subscription.past_due and subscription.recovered.

GET /api/v1/subscription_metrics sums the history over a window (the last 30 days by default), per currency:

  • MRR: the monthly amount of the licensed items of active and past_due subscriptions, before discounts and tax. A yearly price counts a twelfth, a weekly price 52/12 times, a daily price 365/12 times; metered items count as zero.
  • New, expansion, contraction, churned and reactivation MRR: the movements in the window. Net new MRR is their sum.
  • Churn rate: churned MRR divided by MRR at the start of the window.

The brand's home page in the console shows these figures.

Your money, your processor

Payments are charged on your own payment processor account, with the customer's saved payment method. Charges that follow from a change, such as a renewal or an upgrade, happen only after the change is safely recorded, and retrying them is safe: each one is idempotent.

In test mode, test clocks let you move time forward to see trials end, renewals happen and dunning run.