Before you start
- An AgentaOS account and a test API key (
sk_test_...) from Settings → Developers → API Keys. See Accept your first payment if you haven’t. - Card and bank are on by default. Wallet-only accounts cannot sell subscriptions. KYB is only needed for live. See Go live.
4242 4242 4242 4242, any future expiry, any CVC. Never send a card number to the API.
The one id
The dashboard calls this a product. The API creates it withpaymentLinks.create. The id you pass around is linkId.
linkId is what checkouts.create({ linkId }) wants. It is not the /pay/… slug.
1
Create the product once
One product per price. Catalog → Products, or in code:
- SDK
- cURL
amount: 19.99 means €19.99, not cents. Create this once, not once per buyer.From the terminal:
agenta products create --name "Pro" -a 19.99 -c EUR --subscription --interval month --json
returns the same product; its id is the linkId. Needs agentaos 2.1 or newer (npm install -g agentaos@latest).
agenta pay checkout still only makes a one-time checkout.2
Get them to pay
Two ways. Same product. Same
linkId.- Logged-in user
3
Confirm they paid
Shared the Created a checkout for a logged-in user? Prefer the webhook.
/pay/… link? List subscriptions and find them by email:checkout.session.completed includes event.data.metadata. Your customerId is there. So is subscriptionId after they start the card form.subscriptions.list() does not copy your metadata. Later renewals fire the same event without customerId. Look up the user by the subscription.id you stored the first time.Or poll checkouts.retrieve(sessionId) until completed, expired, or cancelled. Verify the signature: Handle webhooks.unitAmountMinor is cents. 1999 means €19.99. Every other amount in this API is already decimal (19.99).4
Status, invoices, cancel
Use the Cancel does not refund. It stops the next renewal. They keep access until
subscription.id.currentPeriodEnd. Pass { atPeriodEnd: false } (CLI: --now) to cancel immediately instead. Calling cancel again is a no-op.PDF: agentaos.invoices.downloadPdf(invoice.id) and agentaos.invoices.getReceipt(invoice.id).- CLI
- cURL
5
Optional: a free trial
A trial is a property of the plan. Add The hosted checkout says “Due today €0.00, then €19.99/mo after your 14-day free trial”, saves the card, and creates the subscription as
trialPeriodDays (1 to 730) when you create it; nothing else changes.trialing. The first charge happens when the trial ends. checkout.session.completed fires at trial start with amount: "0", trial: true and trial_end; treat it as “trial started”, not as money received.6
Optional: upgrade or downgrade
Each price is its own product. To move a subscriber, quote the change, show it, then apply it with the quote’s An upgrade charges the prorated difference on the saved card now and the new price applies immediately. A downgrade charges nothing today; the subscriber keeps the current plan until
prorationDate.- SDK
- CLI
effectiveAt, the current period end, and the subscription reports the switch as pendingPlanChange until then. To cancel a scheduled downgrade, change the plan to the current plan again (direction: 'revert', nothing charged). The target must be a different plan in the same currency and billing interval, and the subscription must be active or trialing. Each of these fires subscription.updated.Verify it worked
subscriptions.list()showsstatus: 'active'and the rightunitAmountMinor.- Shared-link buyer: they used
/pay/…and appear under Customers. - Logged-in buyer: they landed on
/checkout/…. The webhook hasmetadata.customerIdandmetadata.subscriptionId.subscriptions.list()does not containcustomerId. - Cancel sets
cancelAtPeriodEnd: true. Access stays untilcurrentPeriodEnd.
Next steps
Handle webhooks
Verify the signature and handle the same event twice.
Checkouts
checkouts.create({ linkId }) and every field on the session.Subscriptions
List, invoices, and cancel.
Go live
Take this product from test mode to real money.