Subscription schedules
Plan future phases and price changes in advance.
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.
| Need | Use |
|---|---|
| Change price effective immediately | vinr.subscriptions.update |
| Discounted intro period, then full price | Schedule with two phases |
| Annual contract that steps up each year | Schedule with one phase per year |
| Migrate everyone to a new plan at next renewal | Schedule 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
| Event | Emitted when |
|---|---|
subscription_schedule.created | The schedule is created. |
subscription_schedule.updated | Phases are amended. |
subscription_schedule.phase.started | A phase boundary is crossed; payload carries the new items. |
subscription.updated | The backing subscription's prices change at the boundary. |
invoice.created / invoice.paid | The 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
Subscriptions
The full subscription lifecycle.
Trials & proration
How partial periods and boundaries are billed.
Products & prices
Define the prices your phases reference.
Last updated on