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.
import { cancelRenewal } from '@solvapay/next'
export async function POST(request: NextRequest) {
const { purchaseRef, reason } = await request.json()
const result = await cancelRenewal(request, { purchaseRef, reason })
return result instanceof NextResponse ? result : NextResponse.json(result)
}
| Parameter | Type | Required | Description |
|---|
purchaseRef | string | Yes | The purchase reference to cancel |
reason | string | No | Optional cancellation reason |
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).
import { reactivateRenewal } from '@solvapay/next'
export async function POST(request: NextRequest) {
const { purchaseRef } = await request.json()
const result = await reactivateRenewal(request, { purchaseRef })
return result instanceof NextResponse ? result : NextResponse.json(result)
}
| Parameter | Type | Required | Description |
|---|
purchaseRef | string | Yes | The purchase reference to reactivate |
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.
import { activatePlan } from '@solvapay/next'
export async function POST(request: NextRequest) {
const { productRef, planRef } = await request.json()
const result = await activatePlan(request, { productRef, planRef })
return result instanceof NextResponse ? result : NextResponse.json(result)
}
| Parameter | Type | Required | Description |
|---|
productRef | string | Yes | The product to activate |
planRef | string | Yes | The plan to activate on |
Response statuses
| Status | Meaning |
|---|
activated | Purchase created successfully |
already_active | Customer already has an active purchase on this plan |
topup_required | Customer needs more credits — response includes creditBalance and creditsPerUnit |
payment_required | Plan requires payment — response includes checkoutUrl and checkoutSessionId |
invalid | Invalid product or plan reference |
const result = await activatePlan(request, { productRef, planRef })
if (!(result instanceof NextResponse)) {
switch (result.status) {
case 'activated':
// Purchase created — result.purchaseRef is available
break
case 'topup_required':
// Show top-up UI with result.creditBalance and result.creditsPerUnit
break
case 'payment_required':
// Redirect to result.checkoutUrl
break
}
}
Plan switching
When a customer already has an active purchase on a product and you call activatePlan with a different planRef, the SDK automatically:
- Expires the existing purchase (fires
purchase.expired webhook)
- Creates a new purchase on the requested plan (fires
purchase.created webhook)
No special API call is needed — activatePlan handles the switch.
// Customer is on pln_basic, switch to pln_pro
const result = await activatePlan(request, {
productRef: 'prd_myapi',
planRef: 'pln_pro',
})
// result.status === 'activated' if the switch succeeded
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.
Complete Next.js example
app/api/
├── cancel-renewal/route.ts
├── reactivate-renewal/route.ts
├── activate-plan/route.ts
└── ...
// app/api/cancel-renewal/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { cancelRenewal } from '@solvapay/next'
export async function POST(request: NextRequest) {
const { purchaseRef, reason } = await request.json()
const result = await cancelRenewal(request, { purchaseRef, reason })
return result instanceof NextResponse ? result : NextResponse.json(result)
}
// app/api/reactivate-renewal/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { reactivateRenewal } from '@solvapay/next'
export async function POST(request: NextRequest) {
const { purchaseRef } = await request.json()
const result = await reactivateRenewal(request, { purchaseRef })
return result instanceof NextResponse ? result : NextResponse.json(result)
}
// app/api/activate-plan/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { activatePlan } from '@solvapay/next'
export async function POST(request: NextRequest) {
const { productRef, planRef } = await request.json()
const result = await activatePlan(request, { productRef, planRef })
return result instanceof NextResponse ? result : NextResponse.json(result)
}
Next steps
- Webhooks — handle
purchase.updated, purchase.expired, and purchase.created events from lifecycle changes
- Billing — understand billing cycles, renewal processing, and purchase states
- Next.js guide — full Next.js integration walkthrough