Subscriptions
A customer's recurring commitment to one or more prices, billed at the end of each period.
See the subscriptions guide for the billing model, trials and dunning.
The subscription object
sub_.subscriptiontrialing, active, past_due, unpaid, canceled or paused.charge_automatically (saved card) or send_invoice (bank invoice).send_invoice.amount_off or percent_off, duration (once, repeating, forever), and coupon and promotion_code when it came from one.discount.repeating discount stops applying.Quote a subscription
What one period of a subscription on these items would cost, VAT and an optional coupon or promotion code included, before anything is created or redeemed. The lines are at their prices with VAT inside them; the discount comes off their total and VAT is computed on what is paid. A metered price is listed at zero, since its usage is unknown. Use it to check a code, or to know what amount to collect on a checkout session that starts the subscription.
Body
{ price, quantity? }, as on create.first_invoice_total zero and dates the first invoice at the trial's end.{
"object": "subscription_quote",
"currency": "ISK",
"interval": "month",
"interval_count": 1,
"lines": [
{ "price": "price_2Ab4Cd6Ef8Gh0Ij2Kl4Mn6Op", "description": "Pro plan", "quantity": 2, "unit_amount": 4990, "amount": 9980, "tax_rate": 2400, "tax_amount": 1932 }
],
"subtotal": 6438,
"tax": 1546,
"discount": 1996,
"total": 7984,
"tax_breakdown": [{ "tax_rate": 2400, "taxable_amount": 6438, "tax_amount": 1546 }],
"coupon": "cpn_7Hs2Kq9LmW4xZc1Vb8Ny3Rt6",
"promotion_code": "promo_3Vb8Ny1Rt6Hs2Kq9LmW4xZc7",
"discount_duration": "repeating",
"first_invoice_at": "2026-11-22T10:00:00.000Z",
"first_invoice_total": 7984
}Errors: resource_not_found for a price or customer, invalid_field for coupon and promotion_code together or a price listed twice, invalid_price_type for a price that is not recurring, invalid_subscription for items with mixed intervals or currencies, resource_in_wrong_state for a code or coupon that cannot be applied.
Create a subscription
The customer needs a default payment method for charge_automatically, or a kennitala for send_invoice. All items must share an interval and a currency, and at least one must be recurring.
Body
{ price, quantity?, credit_rollover?, included_units?, trial_included_units?, metadata? }. trial_included_units is the item's allowance while trialing; without it the trial has the paid allowance.charge_automatically or send_invoice.send_invoice: days the customer has to pay each invoice.resource_in_wrong_state when it no longer applies.// The customer already has a saved card (payment_method.attached fired).
const subscription = await borga.subscriptions.create({
customer: "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
items: [{ price: "price_2Ab4Cd6Ef8Gh0Ij2Kl4Mn6Op", quantity: 3 }],
collection_method: "charge_automatically",
trial_period_days: 14,
metadata: { plan: "pro" },
});
console.log(subscription.status); // "trialing"
console.log(subscription.current_period_end);curl https://api.borga.is/v1/subscriptions \
-H "Authorization: Bearer sk_test_…" \
-H "Content-Type: application/json" \
-d '{
"customer": "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
"items": [{ "price": "price_2Ab4Cd6Ef8Gh0Ij2Kl4Mn6Op", "quantity": 3 }],
"collection_method": "charge_automatically",
"trial_period_days": 14
}'{
"id": "sub_9Qw1Er3Ty5Ui7Op9As1Df3Gh",
"object": "subscription",
"customer": "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
"status": "trialing",
"collection_method": "charge_automatically",
"days_until_due": null,
"current_period_start": "2026-09-07T12:00:00.000Z",
"current_period_end": "2026-09-21T12:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": null,
"ended_at": null,
"trial_start": "2026-09-07T12:00:00.000Z",
"trial_end": "2026-09-21T12:00:00.000Z",
"pause_collection": null,
"discount": null,
"metadata": { "plan": "pro" },
"items": [
{
"id": "si_5Zx7Cv9Bn1Mq3We5Rt7Yu9Io",
"object": "subscription_item",
"subscription": "sub_9Qw1Er3Ty5Ui7Op9As1Df3Gh",
"price": "price_2Ab4Cd6Ef8Gh0Ij2Kl4Mn6Op",
"quantity": 3,
"credit_rollover": false,
"included_units": null,
"trial_included_units": null,
"metadata": {},
"created_at": "2026-09-07T12:00:00.000Z",
"updated_at": "2026-09-07T12:00:00.000Z"
}
],
"created_at": "2026-09-07T12:00:00.000Z",
"updated_at": "2026-09-07T12:00:00.000Z"
}Errors: invalid_subscription, invalid_price_type, meter_already_subscribed, resource_not_found.
Retrieve a subscription
Update a subscription
Change items through subscription items.
Body
null removes the discount, whichever coupon or code it came from.Cancel a subscription
Body
true keeps the subscription active until current_period_end, bills the final period, then cancels. false ends it now: a final invoice (billing_reason: subscription_cancel) bills metered usage so far and licensed items for the part of the period used.Uncancel a subscription
Clears cancel_at_period_end. Fails with cannot_uncancel if no cancellation is pending.
Pause a subscription
Stops billing. Fails with cannot_pause unless the subscription is active or trialing.
Resume a subscription
Fails with not_paused if the subscription is not paused.
List subscriptions
Query parameters
const id = "sub_9Qw1Er3Ty5Ui7Op9As1Df3Gh";
// Change seats; Borga prorates the difference on the next invoice.
const [item] = (await borga.subscriptions.retrieve(id)).items;
await borga.subscriptionItems.update(item.id, {
quantity: 5,
proration_behavior: "create_prorations",
});
// Add a one-off charge to the next invoice.
await borga.invoiceItems.create({
customer: "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
subscription: id,
amount: 15000,
description: "Onboarding workshop",
});
// Cancel when the period ends (reversible with uncancel).
await borga.subscriptions.cancel(id, { at_period_end: true });
await borga.subscriptions.uncancel(id);
// Pause and resume billing.
await borga.subscriptions.pause(id);
await borga.subscriptions.resume(id);