Paystack Plans
The Plans API lets you create and manage installment/recurring payment options. Plans define the billing cycle, amount, and currency for subscriptions.
Depends on: paystack-setup for the
paystackRequesthelper.
Related: paystack-subscriptions for subscribing customers to plans.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /plan | Create a plan |
| GET | /plan | List plans |
| GET | /plan/:id_or_code | Fetch a plan |
| PUT | /plan/:id_or_code | Update a plan |
Create Plan
POST /plan
| Param | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the plan |
amount | integer | Yes | Amount in subunits (e.g. 500000 = ₦5,000) |
interval | string | Yes | daily, weekly, monthly, quarterly, biannually, annually |
description | string | No | Plan description |
send_invoices | boolean | No | Send invoices to customers (default: true) |
send_sms | string | No | Send SMS to customers (default: true) |
currency | string | No | Currency code e.g. NGN, GHS, ZAR, USD |
invoice_limit | integer | No | Max invoices to raise during subscription |
const plan = await paystackRequest<{
name: string;
plan_code: string;
amount: number;
interval: string;
}>("/plan", {
method: "POST",
body: JSON.stringify({
name: "Pro Plan",
amount: 500000, // ₦5,000
interval: "monthly",
currency: "NGN",
send_invoices: true,
invoice_limit: 0, // 0 = unlimited
}),
});
// plan.data.plan_code → "PLN_gx2wn530m0i3w3m"
List Plans
GET /plan
| Param | Type | Required | Description |
|---|---|---|---|
perPage | integer | No | Records per page (default: 50) |
page | integer | No | Page number (default: 1) |
status | string | No | Filter by plan status |
interval | string | No | Filter by interval |
amount | integer | No | Filter by amount (in subunits) |
const plans = await paystackRequest("/plan?perPage=20&page=1&interval=monthly");
Fetch Plan
GET /plan/:id_or_code
Returns plan details including associated subscriptions array.
const plan = await paystackRequest(
`/plan/${encodeURIComponent("PLN_gx2wn530m0i3w3m")}`
);
Update Plan
PUT /plan/:id_or_code
All body params are the same as Create Plan, plus:
| Param | Type | Required | Description |
|---|---|---|---|
update_existing_subscriptions | boolean | No | Apply changes to existing subscriptions (default: true) |
await paystackRequest(`/plan/${encodeURIComponent("PLN_gx2wn530m0i3w3m")}`, {
method: "PUT",
body: JSON.stringify({
name: "Pro Plan (Updated)",
amount: 750000,
update_existing_subscriptions: false, // Only affect new subscriptions
}),
});
Intervals Reference
| Interval | Description |
|---|---|
daily | Charge every day |
weekly | Charge every 7 days |
monthly | Charge every month |
quarterly | Charge every 3 months |
biannually | Charge every 6 months |
annually | Charge every 12 months |
Common Pattern: SaaS Pricing Setup
async function createPricingTiers() {
const tiers = [
{ name: "Starter", amount: 200000, interval: "monthly" as const },
{ name: "Pro", amount: 500000, interval: "monthly" as const },
{ name: "Enterprise", amount: 2000000, interval: "monthly" as const },
];
const plans = await Promise.all(
tiers.map((tier) =>
paystackRequest("/plan", {
method: "POST",
body: JSON.stringify({
...tier,
currency: "NGN",
send_invoices: true,
}),
})
)
);
return plans.map((p: any) => ({
name: p.data.name,
code: p.data.plan_code,
amount: p.data.amount,
}));
}