agentaos.subscriptions reads and manages subscriptions; it has no create(). A subscription starts when a buyer pays a payment link created with type: 'subscription'. From then on AgentaOS, as merchant of record, bills the buyer every billingInterval by card or bank.
checkout.session.completed carries your customerId and the new subscriptionId in data.metadata. Store the subscriptionId on your user. Renewals do not carry your customerId, so match them by that subscriptionId. See Receive webhooks in Express to verify the event.
See Sell a subscription.
subscriptions.list(params?)
Mirrors the dashboard’s Subscriptions list, scoped to the environment (test or live) your API key belongs to.
number
default:"20"
Max 100.
number
default:"0"
string
Only the subscribers who redeemed this code. The code as the buyer types it, not case-sensitive.
PaginatedList<Subscription>.
Read one subscription
There is noretrieve(id). Store the subscription’s id when the first checkout.session.completed arrives: it is metadata.subscriptionId on that event. To read the subscription later, page through list() and find it:
Subscription fields
string
The subscription’s id, a UUID. The same value as
metadata.subscriptionId on the checkout event and id on the subscription events.string | null
string | null
string | null
The product name or description.
'month' | 'year' | null
SubscriptionStatus
See statuses below.
number
Per-cycle amount in integer minor units:
1999 means €19.99. See the money model.string
string | null
ISO 8601.
null before the first billing cycle has booked.string | null
The underlying subscription ID from the card processor.
string
The plan’s payment link
id, a UUID: the value checkouts.create({ linkId }) takes and Copy link ID on the product page copies. It is not the token in the checkout URL, which checkout.session.completed sends as linkId.object | null
Null unless a downgrade is scheduled. Then
{ linkId, planName, unitAmountMinor, effectiveAt }: the plan the subscription switches to at effectiveAt (the period end). planName, unitAmountMinor and linkId above stay what the buyer paid for until then, so gate access on them, not on the pending change.boolean
string | null
string | null
object | null
{ code, kind } when the subscriber redeemed a discount code, else null. kind is discount or tracking (a code that takes nothing off). What the code took off is on the first invoice.Statuses
SubscriptionStatus is the card processor’s status for the subscription. AgentaOS reads it on a schedule, so a change shows here after the next check. It has eight values. Webhook events never carry incomplete or incomplete_expired, because a subscription that never activated sends no event.
subscriptions.invoices(id)
Each billing cycle’s invoice, newest first.
string
string
string
string
number
Currency units.
string
boolean
boolean
Free trials
A trial is a property of the product, not of the subscription: create the plan withtrialPeriodDays (1 to 730). At checkout the buyer’s card is saved with nothing due today, the subscription is created as trialing, and the first charge happens when the trial ends, after which it is active.
checkout.session.completedfires when the card is saved, withamount: "0". Treat it as “trial started”, not as money received. The wire body also hastrial: trueandtrial_end(ISO 8601), whichverify()returns astrialandtrialEnd. The SDK type does not declare them yet: read them through a wider type, or readevent.data.metadata.trial, which is alsotrue.subscriptions.list()showsstatus: 'trialing'and the plan’sunitAmountMinor;currentPeriodEndis the trial end while trialing.- When the trial ends and the first charge succeeds,
checkout.session.completedandsubscription.renewedfire. See Event order for subscriptions. - Canceling during the trial stops it before any charge.
subscriptions.previewPlanChange(id, targetLinkId)
Quote moving a subscription to another plan. Read-only: nothing is charged or scheduled. The target must be a different subscription product in the same currency and billing interval, and the subscription must be active or trialing; anything else is a 400.
'upgrade' | 'downgrade' | 'revert'
upgrade when the new plan costs more per cycle, downgrade when it costs the same or less, revert when the target is the current plan while a downgrade is pending.string
number
Integer minor units charged now. Always
0 for a downgrade.number
string
ISO 8601. Upgrade: now. Downgrade: the current period end.
number
The next regular cycle invoice on the new plan, integer minor units.
number
string
ISO 8601.
number
Unix seconds. Echo it in
changePlan so the charge matches this quote.subscriptions.changePlan(id, { targetLinkId, prorationDate })
Apply a quoted plan change. An upgrade charges the prorated difference on the saved card now; a downgrade charges nothing today and switches at the current period end. Idempotent on (subscription, target plan, prorationDate).
agenta subscriptions change-plan <id> --to <linkId> (add --dry-run for the quote only).
Canceling a scheduled downgrade. Change the plan to the current plan again. The preview and the result come back with direction: 'revert', nothing is charged, and pendingPlanChange is null afterwards. Targeting the plan that is already pending returns 400 (“already scheduled”).
Webhooks. Every plan change fires subscription.updated on your account’s webhook URL: when a downgrade is scheduled (data.pendingPlan is set), when it is reverted (pendingPlan back to null), when an upgrade is applied, and when the scheduled plan takes over at the period end. See Events.
subscriptions.cancel(id)
The cancellation always takes effect at the end of the current period: there is no immediate cancel. The subscriber keeps access until currentPeriodEnd. No refund. Calling it again is a no-op.
Response
SubscriptionStatus
Status after the cancellation call.
string | null
ISO 8601.
boolean
Whether it’s scheduled to cancel at period end vs. already canceled.
string | null
ISO 8601 date the cancellation takes (or took) effect.
subscriptions.credit(id, { amountMinor, reason, idempotencyKey })
Put credit on the subscriber’s account. It comes off their next invoice and lowers what the card is charged. It is not a refund: no money goes back to the card. The client must be signed in as an owner or admin; an API key is refused with 403.
number
required
Positive integer minor units. There is no currency field: the subscription’s currency is used. At most the whole next invoice.
string
required
Why you give it. The subscriber never sees it.
string
required
One key per credit you mean to give. Send the same key again when you retry after a timeout; a new key gives a second credit.
string
The ledger entry id.
number
string
string
number
All unspent credit this buyer has with you now.
number
What the next invoice would have charged before this credit.
number
What it charges after it.
string
ISO 8601.
string
The id of the person who gave it.
string
ISO 8601.
active or trialing, not scheduled to cancel, and without a pending plan change; otherwise the call returns 400. While the buyer has credit left, previewPlanChange and changePlan return 400 until the next invoice.
subscriptions.credits(id)
The credits given on this subscription, newest first, and what is still unspent. Owner or admin only, like credit.
CreditEntry[]
{ id, amountMinor, reason, createdBy, createdAt } for each credit.number
Unspent credit on the buyer, shared by every subscription they have with you.
Next steps
Sell a subscription
Create a product, share the link or check out a logged-in user.
Payment links
Create the
type: 'subscription' link that starts a subscription.Customers
The people paying your subscriptions.
Invoices
Each renewal charge issues its own invoice.
Errors
What
cancel() throws on an unknown subscription ID.