# Subscriptions

> Recurring billing with fixed and seat-based prices, trials, proration, discounts and bank-invoice collection.

Source: https://docs.borga.is/billing/subscriptions

A **Subscription** (`sub_…`) bills a Customer for one or more Prices on a schedule. Borga owns the cycle: at the end of each period it builds an invoice for what was used, books it in your accounting system, and collects it from the customer's saved card or by bank invoice. Failed charges are retried automatically.

## Building blocks

| Object | Purpose |
| --- | --- |
| Product (`prod_`) | What you sell, for example "Pro plan". |
| Price (`price_`) | How much and how often: `unit_amount`, `currency`, `recurring.interval`. A product can have several prices. |
| Customer (`cus_`) | Who pays. Needs a saved card for `charge_automatically`, or a kennitala for `send_invoice`. |
| Subscription (`sub_`) | The customer's commitment to a set of prices. |
| Subscription item (`si_`) | One price within the subscription, with a `quantity` (seats). |

Create the catalogue once:

```ts Node.js
const product = await borga.products.create({
  name: "Pro plan",
  description: "Everything in Starter plus priority support",
});

const monthly = await borga.prices.create({
  product: product.id,
  type: "recurring",
  currency: "ISK",
  unit_amount: 4990, // 4.990 kr. per seat per month
  recurring: { interval: "month", interval_count: 1 },
});

const yearly = await borga.prices.create({
  product: product.id,
  type: "recurring",
  currency: "ISK",
  unit_amount: 49900,
  recurring: { interval: "year" },
});
```

Every item in a subscription must share the same billing interval and currency. Quarterly and half-yearly plans use `interval: "month"` with `interval_count` 3 or 6.

## Billing model

Borga bills **in arrears**: when a period ends, it issues an invoice for that period (licensed items times quantity, metered usage, prorations and one-off items) and collects it. The invoice appears as `draft`, is finalised in your accounting provider, then paid.

A trial period is free. The subscription is `trialing` until the trial ends, becomes `active`, and the first paid period is billed when it ends.

## Start a subscription

### From a checkout session

The simplest path when the customer does not have a saved card yet. Pass `subscription` on a hosted session: the checkout collects and saves the card, charges the session `amount` immediately, and creates the subscription when the payment succeeds.

```ts Node.js
// One hosted session collects the card, charges the first period and
// starts the subscription. The card is saved automatically.
const session = await borga.paymentSessions.create({
  amount: 4990,
  currency: "ISK",
  customer: "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
  subscription: {
    items: [{ price: "price_2Ab4Cd6Ef8Gh0Ij2Kl4Mn6Op", quantity: 3 }],
  },
  return_url: "https://yoursite.is/billing/welcome",
  cancel_url: "https://yoursite.is/pricing",
});

// Redirect to session.url. Listen for subscription.created.
```

The session `amount` is a separate, immediate charge recorded on the subscription's metadata as `initial_payment_id`. Because periods are billed when they end, use it for a setup fee or a small verification amount rather than the first period. You receive `payment.succeeded`, `payment_method.attached`, `subscription.created` and `subscription.active`.

### From the API

When the customer already has a saved card (see [Saved cards](/payments/saved-cards)), create the subscription directly. The customer's default payment method is charged each period.

```ts Node.js
// 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);
```
```bash curl
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
  }'
```

### Collect by bank invoice

Set `collection_method` to `send_invoice` and a `days_until_due`. Each period Borga issues a krafa through PayDay to the customer's kennitala instead of charging a card. Requires bank invoices to be enabled; see [Bank invoices](/payments/bank-invoices).

```ts Node.js
// Bill by bank invoice: each period Borga issues a krafa through the
// merchant's accounting provider and the customer pays it in their bank.
const subscription = await borga.subscriptions.create({
  customer: "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz", // needs a kennitala
  items: [{ price: "price_2Ab4Cd6Ef8Gh0Ij2Kl4Mn6Op" }],
  collection_method: "send_invoice",
  days_until_due: 14,
});
```

## Change a subscription

```ts Node.js
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);
```

- **Seats.** Update the item's `quantity`. With `proration_behavior: "create_prorations"` (default) the difference for the rest of the period is added to the next invoice; `always_invoice` bills it right away; `none` skips proration.
- **Add or remove prices.** Create or delete subscription items with the same `proration_behavior` options.
- **One-off charges.** Create an invoice item on the subscription; it lands on the next invoice. Negative amounts are credits.
- **Discounts.** `discount` takes `amount_off` or `percent_off`. Today the only `duration` is `once`, applied to the next invoice.
- **Cancel.** `cancel` with `at_period_end: true` sets `cancel_at_period_end` and bills a final invoice for the current period; `uncancel` reverses it. Without the flag the subscription ends immediately.
- **Pause and resume.** `pause` stops billing; `resume` picks up with the same anchor.

Every change emits `subscription.updated`; see the [event catalog](/api/events).

## Statuses

| Status | Meaning |
| --- | --- |
| `trialing` | In a free trial. Becomes `active` when it ends. |
| `active` | Billing normally. |
| `past_due` | A charge failed and retries were exhausted, or a bank invoice went overdue. Billing continues; a later successful payment returns it to `active`. |
| `unpaid` | Reserved for future dunning policy; not set today. |
| `paused` | Paused by you. No invoices are created. |
| `canceled` | Ended. Final invoice issued if the cancellation was at period end. |

## Failed payments

When a card charge for an invoice fails, Borga emits `invoice.payment_failed` and retries after 1, 3, 5 and 7 days (cumulative days 1, 4, 9 and 16 after the first failure). Each attempt emits another `invoice.payment_failed` with the attempt number, and the last one carries `final: true`. When the schedule is exhausted the subscription moves to `past_due` and `subscription.past_due` fires. Use these events to prompt the customer to update their card; a new saved card set as default is used by the next attempt.

For `send_invoice` subscriptions, an invoice that passes its due date emits `invoice.overdue` and also moves the subscription to `past_due`.

## Invoices for subscriptions

Each cycle emits `invoice.created`, then `invoice.finalized` once the accounting provider has accepted it, then `invoice.paid` or `invoice.payment_failed`. Invoice line items carry the price's `accounting_code` if set, so revenue lands on the right account. See [Invoicing](/billing/invoicing) and the [Invoices API](/api/invoices).
