Skip to main content

Overview

After a customer completes checkout, the SDK provides helpers to manage the full purchase lifecycle:
  • Cancel renewal — stop auto-renewal; access continues until the period ends
  • Reactivate renewal — undo a pending cancellation while still in the active period
  • Activate plan — activate a product for a customer on a specific plan without checkout (free units or credit balance)
  • Plan switching — activating a different plan automatically expires the current purchase and creates a new one
All helpers follow the same pattern: pass the incoming Request object and a body, get back either a data object or a NextResponse error.

Cancel renewal

Cancels auto-renewal on a purchase. The customer keeps access until the current billing period ends.
The purchase remains active with cancelledAt set. When the billing period ends, the purchase transitions to expired.

Reactivate renewal

Undoes a pending cancellation, restoring auto-renewal. Only works while the purchase is still active (before the period ends).
Preconditions:
  • Purchase status must be active
  • cancelledAt must be set (cancellation is pending)
  • endDate must not have passed
On success, cancelledAt is cleared and autoRenew is restored. A purchase.updated webhook fires.

Activate plan

Activates a product for a customer on a specific plan without going through checkout. Useful for free plans, credit-based activation, or programmatic plan assignment. Usage-based (PAYG) plans are topup-first: a customer whose credit balance does not cover at least one unit receives topup_required and no purchase is created. Route them through a top-up first, then re-run activatePlan to create the active purchase. Free plans activate immediately; paid recurring / hybrid plans return payment_required.

Response statuses

Plan switching

When a customer already has an active purchase on a product and you call activatePlan with a different planRef, the SDK automatically:
  1. Expires the existing purchase (fires purchase.expired webhook)
  2. Creates a new purchase on the requested plan (fires purchase.created webhook)
No special API call is needed — activatePlan handles the switch.
Plan switching immediately expires the old purchase. If the old plan was a paid recurring plan, consider whether you need to handle proration or credits on your side.

Automatic top-ups (auto-recharge)

When activatePlan returns topup_required, the customer is out of credits and needs to buy more before they can continue. Two things belong on that surface:
  1. A top-up UI so they can add credits now.
  2. An optional auto-recharge toggle so the balance refills automatically next time.
The customer-facing components (TopupForm, AutoRecharge) and hooks (useTopup, useAutoRecharge) live in @solvapay/react — see Credit Top-Ups & Auto-Recharge in the React guide. This section covers the server-side helpers that back them; the dedicated Auto-recharge guide walks through the full stack, including the monthly spend cap and the @solvapay/server 2.0.0 migration.

Configuration helpers

Auto-recharge config is read and written through three helpers, exposed as GET / PUT / DELETE on a single /api/auto-recharge route:

Top-up payment helpers

Top-ups reuse the payment-intent flow. createTopupPaymentIntent accepts an optional autoRecharge payload so auto-recharge can be armed in the same charge as the initial card payment (no separate card-setup step), and processTopupPaymentIntent confirms the credit landed:

AutoRechargeInput parameters

saveAutoRecharge (and the autoRecharge field on createTopupPaymentIntent) accept an AutoRechargeInput: SaveAutoRechargeInput also accepts deferSetupIntent?: boolean — set it to stage the config without creating a SetupIntent (used by the combined top-up + auto-recharge flow). Validation enforces both amounts <= 10,000 major units and a per-currency Stripe minimum on the top-up amount.

Routes to wire

Behavior notes

  • Credits mint on charge success. Credits are booked when the off-session charge succeeds; the webhook is an idempotent backstop, not the primary path.
  • Deferred setup stages the config. With deferSetupIntent / deferCardSetup, the config is pending_setup and is not armed until the card is saved on the top-up charge and the status flips to active.
  • Live FX, no stored credit threshold. The threshold is stored in display-currency minor units and re-resolved to credits at trigger time — there’s no persisted thresholdCredits.
  • Monthly spend cap. An optional maxMonthlySpendMajor limits how much auto-recharge spend is allowed per UTC calendar month. The config stays active when the cap is hit — charges resume automatically next month. The <AutoRecharge> component exposes the cap under Advanced and shows current-period spend on the summary card; read monthlySpendMinor / monthlySpendPeriod on the config when building a custom UI.
autoRecharge.triggered: true on a usage/debit response means an off-session charge was initiated — it does not mean credits were booked inline in that same response. Off-session declines are delivered via the customer.credit.auto_topup_failed webhook, not in the usage/debit response. Pair the webhook with useAutoRecharge().config.status === 'failed' to prompt the customer to update their card.

Complete Next.js example

Next steps

  • Auto-recharge — the full auto-recharge stack, monthly spend cap semantics, and the 2.0.0 migration
  • Credit Top-Ups & Auto-Recharge — the React components and hooks (TopupForm, AutoRecharge, useTopup, useAutoRecharge) that drive the top-up UI
  • Webhooks — handle purchase.updated, purchase.expired, and purchase.created events from lifecycle changes, plus customer.credit.auto_topup_failed for off-session declines
  • Billing — understand billing cycles, renewal processing, and purchase states
  • Next.js guide — full Next.js integration walkthrough