Creating subscriptions

Start a subscription with prices, trials, and a payment method.

View as MarkdownInstall skills

Create a subscription by attaching a customer, one or more prices, and a payment method, with optional trial and proration behavior. Once created, the subscription becomes the engine that generates invoices each cycle — so getting the first call right means recurring revenue collects itself.

What you need firstAsk

A subscription ties three things together. Have each ready before you call the API:

IngredientPrefixCreated where
A customercust_Customers
One or more recurring pricesprice_Products & prices
A default payment methodpm_Attached to the customer or passed at creation

Prices must be recurring (have a recurring.interval). A one-time price belongs on an invoice item, not a subscription.

Create your first subscriptionAsk

The minimal call attaches a customer to a price. VINR uses the customer's default payment method and anchors the billing cycle to the creation time.

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

const subscription = await vinr.subscriptions.create({
  customer: 'cust_8Hk2pQ',
  items: [{ price: 'price_pro_monthly', quantity: 1 }],
});

console.log(subscription.id);     // "sub_..."
console.log(subscription.status); // "active"

If the customer has no default payment method, pass one explicitly. The method is attached to the customer and set as default for future cycles:

const subscription = await vinr.subscriptions.create({
  customer: 'cust_8Hk2pQ',
  items: [{ price: 'price_pro_monthly' }],
  default_payment_method: 'pm_card_visa',
});

What happens on creationAsk

VINR validates and creates the subscription

The customer, prices, and payment method are checked. The subscription is created with a billing_cycle_anchor (defaults to now).

The first invoice is generated and finalized

Unless the subscription is in a trial, VINR immediately creates a draft invoice, applies any discounts and tax, and finalizes it.

The first invoice is collected

The finalized invoice is paid against the default method. This may require SCA — handle the requires_action outcome client-side.

Status settles

On success the subscription becomes active and VINR emits subscription.created and invoice.paid. If collection fails, the subscription enters past_due and dunning begins.

Adding a trialAsk

A trial delays the first charge. The subscription is trialing until the trial ends, then VINR collects the first real invoice automatically. Use either a duration or an explicit end timestamp.

const subscription = await vinr.subscriptions.create({
  customer: 'cust_8Hk2pQ',
  items: [{ price: 'price_pro_monthly' }],
  trial_period_days: 14,
});
// status: "trialing" — no invoice collected yet
const subscription = await vinr.subscriptions.create({
  customer: 'cust_8Hk2pQ',
  items: [{ price: 'price_pro_monthly' }],
  trial_end: 1751328000, // Unix seconds; first charge lands here
});

Collecting a payment method up front during a trial is strongly recommended. Without one, the subscription lapses into past_due the moment the trial ends and no card is on file. See Trials & proration.

Key parametersAsk

Prop

Type

Aligning the billing cycleAsk

By default each subscription bills on its own creation date. To align many customers to a single date (for example, everyone on the 1st), set an explicit billing_cycle_anchor. VINR prorates the partial first period unless you pass proration_behavior: 'none'.

const subscription = await vinr.subscriptions.create({
  customer: 'cust_8Hk2pQ',
  items: [{ price: 'price_pro_monthly' }],
  billing_cycle_anchor: 1751328000, // first day of next month, 00:00 UTC
  proration_behavior: 'create_prorations',
});

React with webhooks, not the responseAsk

The create call returns the subscription, but collection can complete asynchronously (SCA, bank delays). Provision access on the event, not the API return value.

const event = vinr.webhooks.verify(payload, request.headers['x-vinr-signature']);

switch (event.type) {
  case 'subscription.created':
    // subscription exists — may still be collecting its first invoice
    break;
  case 'invoice.paid':
    grantAccess(event.data.object.customer); // safe to fulfil here
    break;
  case 'invoice.payment_failed':
    // dunning has begun; surface a recovery prompt
    break;
}

Edge casesAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page