Managing subscriptions

Add items, change quantities, and update metadata.

View as MarkdownInstall skills

Update a running subscription — change quantities, add or remove items, swap prices, and edit metadata — with predictable proration. This page covers the subscriptions.update API and how each change lands on the next invoice.

What you can changeAsk

A subscription is a container of subscription items, each pairing a price with a quantity. Most edits are a mutation of that item list plus subscription-level settings.

ChangeHowBilling impact
Quantity (seats, units)Update an item's quantityProrated
Swap plan (price)Update an item's priceProrated
Add a line (add-on)Append a new itemProrated
Remove a lineDelete an itemProrated credit
Metadata, fieldsUpdate the subscriptionNone

Quantity, price, and item changes generate proration line items — a credit for unused time on the old rate and a charge for the new one. See Trials & proration for the math.

Identifying itemsAsk

Every subscription item has its own si_-prefixed id. Fetch the subscription first so you know which item to mutate.

import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

const sub = await vinr.subscriptions.retrieve('sub_8Q2k...');
sub.items.forEach((item) => {
  console.log(item.id, item.price, item.quantity); // "si_..." "price_..." 3
});

Changing quantityAsk

The most common edit: a customer adds seats. Update the item by id.

const updated = await vinr.subscriptions.update('sub_8Q2k...', {
  items: [{ id: 'si_47xR...', quantity: 5 }],
  prorationBehavior: 'create_prorations', // default
});

prorationBehavior controls how mid-cycle changes are billed:

Prop

Type

Swapping a price (upgrade or downgrade)Ask

To move a customer between plans, replace the item's price. Keep the same item id so VINR treats it as a swap rather than an add + remove.

await vinr.subscriptions.update('sub_8Q2k...', {
  items: [{ id: 'si_47xR...', price: 'price_proYearly' }],
});

Changing recurring.interval (e.g. monthly to yearly) resets the billing cycle anchor to now and invoices the remaining balance immediately. To preserve the original anchor, set billingCycleAnchor: 'unchanged'.

Adding and removing itemsAsk

Append an add-on by passing an item with no id; remove one by passing deleted: true.

await vinr.subscriptions.update('sub_8Q2k...', {
  items: [
    { price: 'price_supportAddon', quantity: 1 }, // add
    { id: 'si_oldAddon', deleted: true },         // remove
  ],
});

A subscription with no remaining active items is invalid — to end billing entirely, cancel the subscription instead of deleting its last item.

Updating metadataAsk

Metadata changes never affect billing and never prorate. Use them to track internal references.

await vinr.subscriptions.update('sub_8Q2k...', {
  metadata: { account_owner: 'team-emea', crm_id: 'AC-4192' },
});

Resulting eventsAsk

Each update emits events you can react to from a webhook endpoint:

EventWhen
subscription.updatedAny item, quantity, price, or metadata change.
invoice.createdA proration draft invoice is generated (with always_invoice).
invoice.paidThe proration invoice is collected.
const event = vinr.webhooks.verify(payload, signatureHeader); // x-vinr-signature
if (event.type === 'subscription.updated') {
  const sub = event.data.object;
  syncEntitlements(sub.customer, sub.items); // grant/revoke seats
}

Always reconcile entitlements from subscription.updated, not from your API response — the webhook is the source of truth and fires even when changes originate from the dashboard or dunning.

Edge casesAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page