Subscription schedules

Plan future phases and price changes in advance.

View as MarkdownInstall skills

A schedule is a timeline attached to a subscription. You define a sequence of phases — an intro price for three months, then a standard price thereafter — and VINR transitions between them automatically at the right moment, with no manual update at switchover. Use schedules whenever a future change is already known: promotional ramps, contracted price increases, plan migrations on renewal.

When to use a scheduleAsk

A plain subscription update changes billing now. A schedule changes billing later, deterministically, and can chain several changes in one object.

NeedUse
Change price effective immediatelyvinr.subscriptions.update
Discounted intro period, then full priceSchedule with two phases
Annual contract that steps up each yearSchedule with one phase per year
Migrate everyone to a new plan at next renewalSchedule anchored to the cycle

PhasesAsk

Each phase declares the prices in effect, how long it lasts, and how to handle the boundary. Phases run back to back: the end_date of one is the start_date of the next, so there are no gaps.

Prop

Type

A phase ends when its iterations are exhausted or its end_date arrives — set exactly one. The final phase may omit both, meaning "continue indefinitely on these prices."

How it worksAsk

Create the schedule

You can wrap an existing subscription or let VINR create one from the first phase. The first phase's start is the schedule's start_date (defaults to now).

VINR drives the timeline

At each phase boundary VINR ends the current phase, applies the next phase's prices, and (per proration_behavior) writes proration line items onto the upcoming invoice. No webhook handler or cron on your side is required.

Phases bill on the normal cycle

A schedule does not change the billing cycle anchor. Invoices still finalize and collect on the subscription's existing dates — the schedule only controls which prices apply.

The schedule completes or releases

When the last bounded phase ends, behavior depends on end_behavior: release detaches the schedule and leaves the subscription running on the final prices; cancel cancels the subscription.

Example: intro price, then standardAsk

A 3-cycle launch discount at €10/month, then €20/month indefinitely.

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

const schedule = await vinr.subscriptionSchedules.create({
  customer: 'cust_8sJ2kLpQ',
  start_date: 'now',
  end_behavior: 'release',          // keep billing after the last phase
  phases: [
    {
      items: [{ price: 'price_intro10', quantity: 1 }],  // €10.00
      iterations: 3,                 // three monthly cycles
    },
    {
      items: [{ price: 'price_std20', quantity: 1 }],    // €20.00
      proration_behavior: 'create_prorations',
      // no iterations / end_date -> runs indefinitely
    },
  ],
});

console.log(schedule.id);            // "sub_sched_..."  -> backing sub_...

The same call over raw REST:

curl https://sandbox.api.vinr.com/v1/subscription_schedules \
  -H "X-Api-Key: $VINR_SECRET_KEY" \
  -d customer=cust_8sJ2kLpQ \
  -d start_date=now \
  -d end_behavior=release \
  -d "phases[0][items][0][price]=price_intro10" \
  -d "phases[0][iterations]=3" \
  -d "phases[1][items][0][price]=price_std20"

Amending a running scheduleAsk

To change a future phase, fetch the schedule and resubmit the full phases array — VINR diffs it. Phases that have already elapsed are immutable; only the current and future phases can be edited.

await vinr.subscriptionSchedules.update('sub_sched_3Vx9', {
  phases: [
    // current phase must be repeated as-is to preserve history
    { items: [{ price: 'price_intro10', quantity: 1 }], iterations: 3 },
    // raise the standard tier and add a discount for one year
    {
      items: [{ price: 'price_std25', quantity: 1 }],
      coupon: 'rwd_loyalty10',
      iterations: 12,
    },
  ],
});

Resulting eventsAsk

EventEmitted when
subscription_schedule.createdThe schedule is created.
subscription_schedule.updatedPhases are amended.
subscription_schedule.phase.startedA phase boundary is crossed; payload carries the new items.
subscription.updatedThe backing subscription's prices change at the boundary.
invoice.created / invoice.paidThe new phase bills on the normal cycle.

Fulfil entitlement changes on subscription_schedule.phase.started rather than guessing dates client-side. Always verify the signature first:

const event = vinr.webhooks.verify(payload, req.headers['x-vinr-signature']);
if (event.type === 'subscription_schedule.phase.started') {
  const phase = event.data.object.current_phase;
  await grantEntitlements(event.data.object.customer, phase.items);
}

Edge casesAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page