Cancellations

Cancel immediately or at period end.

View as MarkdownInstall skills

Cancel a subscription now or schedule it for period end, controlling whether the customer keeps access until they have paid for, how the final invoice is settled, and whether any unused time is refunded.

Two cancellation modesAsk

Every cancellation answers one question: does access end now or at the end of the period the customer already paid for? VINR models this with a single field rather than two endpoints.

ModeFieldAccess endsFinal invoice
At period end (recommended)cancel_at_period_end: trueAt current_period_endNo new invoice; the current paid period runs out
Immediatelyvinr.subscriptions.cancel(...)Right awayOptionally prorate a credit for unused time

Scheduling at period end is reversible — set cancel_at_period_end: false before the period ends and the subscription continues as normal. An immediate cancel is terminal; the subscription moves to canceled and a new subscription is required to resume.

How it worksAsk

A subscription tracks the window it has billed for as current_period_start and current_period_end. Cancellation never deletes history — it sets the subscription's status and a canceled_at timestamp, and the behaviour depends on the mode.

Schedule or execute

cancel_at_period_end: true leaves status: active but stamps cancel_at with the current period end. An immediate cancel transitions status to canceled synchronously.

Settle the final invoice

For period-end cancellation no further invoice is generated; the customer simply stops being billed on the next cycle. For an immediate cancel with proration, VINR issues a credit line item for the unused portion of the current period.

Stop future cycles

Once canceled, the subscription generates no new draft invoices and triggers no further dunning.

React on the event

VINR emits subscription.updated when you schedule, and subscription.deleted when access actually ends. Revoke entitlements on subscription.deleted, not on the schedule.

Schedule cancellation at period endAsk

The customer keeps everything they paid for and is not billed again. This is the default for self-service "cancel my plan" flows.

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

const sub = await vinr.subscriptions.update('sub_8Qd1Kf2pLm', {
  cancel_at_period_end: true,
});

console.log(sub.status);              // "active"
console.log(sub.cancel_at_period_end); // true
console.log(sub.current_period_end);   // unix ts — access ends here

To undo a scheduled cancellation while the period is still running:

await vinr.subscriptions.update('sub_8Qd1Kf2pLm', {
  cancel_at_period_end: false,
});

Cancel immediatelyAsk

Use this when access must stop at once — fraud, an offboarding, or a downgrade to nothing. By default the time the customer already paid for is forfeited; pass prorate: true to credit the unused portion back.

const canceled = await vinr.subscriptions.cancel('sub_8Qd1Kf2pLm', {
  prorate: true,            // credit unused time to the customer
  invoice_now: true,        // finalize the prorated credit immediately
});

console.log(canceled.status);       // "canceled"
console.log(canceled.canceled_at);  // unix ts of cancellation
curl -X POST https://api.vinr.com/v1/subscriptions/sub_8Qd1Kf2pLm/cancel \
  -H "X-Api-Key: $VINR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prorate": true, "invoice_now": true }'

prorate: true credits unused time but does not automatically refund the original payment. The credit lands on the customer's balance and offsets future invoices. To return money to the card, issue an explicit refund for the prorated amount.

Resulting eventsAsk

ActionEvents emittedWhen
Schedule at period endsubscription.updatedImmediately
Period end reachedsubscription.deletedAt current_period_end
Cancel immediatelysubscription.deletedImmediately
Immediate cancel with prorationsubscription.deleted, invoice.createdImmediately

Always gate entitlement revocation on subscription.deleted so a customer who downgrades from a scheduled cancel is not locked out early.

export async function POST(req: Request) {
  const payload = await req.text();
  const signature = req.headers.get('x-vinr-signature') ?? '';
  const event = vinr.webhooks.verify(payload, signature);

  if (event.type === 'subscription.deleted') {
    await revokeAccess(event.data.object.customer); // "cust_..."
  }
  return new Response(null, { status: 200 });
}

Edge casesAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page