skills/paystack-setup/SKILL.md
Set up the Paystack API client, environment variables, and TypeScript helpers for server-side payment integration. Use this skill whenever starting a new Paystack integration, configuring API keys, creating a reusable fetch wrapper for the Paystack REST API, or setting up the foundation for any Paystack feature. Also use when you see errors related to missing PAYSTACK_SECRET_KEY, authentication failures, or need to understand Paystack's base URL, response format, pagination, currencies, or amount subunit conversion.
npx skillsauth add rexedge/paystack paystack-setupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Set up the foundational Paystack API client and environment configuration for TypeScript/JavaScript server-side applications.
| Property | Value |
| --- | --- |
| Base URL | https://api.paystack.co |
| Auth Header | Authorization: Bearer SECRET_KEY |
| Content Type | application/json |
| Response Format | { status: boolean, message: string, data: object } |
| Amount Unit | Subunit of currency (multiply display amount × 100) |
| Transaction ID | Unsigned 64-bit integer — use string in TypeScript |
| Currency | Code | Subunit | Multiplier | | --- | --- | --- | --- | | Nigerian Naira | NGN | kobo | ×100 | | US Dollar | USD | cent | ×100 | | Ghanaian Cedi | GHS | pesewa | ×100 | | South African Rand | ZAR | cent | ×100 | | Kenyan Shilling | KES | cent | ×100 | | West African CFA | XOF | — | ×100 | | Egyptian Pound | EGP | piaster | ×100 | | Rwandan Franc | RWF | — | ×100 |
Create a .env file (or .env.local for Next.js):
PAYSTACK_SECRET_KEY=sk_test_xxxxx # Server-side only, NEVER expose to client
NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY=pk_test_xxxxx # Safe for client-side (Popup/InlineJS)
The secret key (sk_*) must NEVER appear in client-side code, browser bundles, or public repositories. The public key (pk_*) is safe for front-end use with Paystack Popup/InlineJS only.
Test keys start with sk_test_ / pk_test_. Live keys start with sk_live_ / pk_live_. Get them from the Paystack Dashboard under Settings → API Keys & Webhooks.
# For client-side Popup/InlineJS checkout
npm install @paystack/inline-js
# Or with pnpm / yarn
pnpm add @paystack/inline-js
yarn add @paystack/inline-js
No server-side SDK is needed — use the built-in fetch API with the helper below.
Create a reusable, type-safe Paystack client. Every other Paystack skill depends on this pattern:
// lib/paystack.ts
const PAYSTACK_SECRET_KEY = process.env.PAYSTACK_SECRET_KEY;
if (!PAYSTACK_SECRET_KEY) {
throw new Error("PAYSTACK_SECRET_KEY is not set in environment variables");
}
export interface PaystackResponse<T = unknown> {
status: boolean;
message: string;
data: T;
}
export interface PaystackListResponse<T = unknown> {
status: boolean;
message: string;
data: T[];
meta: {
total: number;
skipped: number;
perPage: number;
page: number;
pageCount: number;
};
}
export class PaystackError extends Error {
constructor(
message: string,
public statusCode: number,
public response?: unknown
) {
super(message);
this.name = "PaystackError";
}
}
export async function paystackRequest<T>(
endpoint: string,
options: RequestInit = {}
): Promise<PaystackResponse<T>> {
const url = `https://api.paystack.co${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
Authorization: `Bearer ${PAYSTACK_SECRET_KEY}`,
"Content-Type": "application/json",
...options.headers,
},
});
const data = await response.json();
if (!response.ok) {
throw new PaystackError(
data.message || `Paystack API error: ${response.status}`,
response.status,
data
);
}
return data as PaystackResponse<T>;
}
All list endpoints accept perPage (default: 50, max: 100) and page (default: 1) as query parameters. The response includes a meta object:
{
"meta": {
"total": 243,
"skipped": 0,
"perPage": 50,
"page": 1,
"pageCount": 5
}
}
Build paginated queries like so:
const params = new URLSearchParams({
perPage: "20",
page: "2",
from: "2024-01-01T00:00:00.000Z",
to: "2024-12-31T23:59:59.000Z",
});
const result = await paystackRequest<Transaction[]>(`/transaction?${params}`);
Always convert display amounts to subunits before sending to Paystack, and convert back when displaying:
// Display → Paystack (multiply by 100)
const amountInKobo = Math.round(amountInNaira * 100);
// Paystack → Display (divide by 100)
const amountInNaira = amountInKobo / 100;
Use Math.round() to avoid floating-point issues like 19.99 * 100 = 1998.9999999999998.
| Method | Usage | | --- | --- | | POST | Create resources, initiate actions | | GET | Fetch, list, verify resources | | PUT | Update resources | | DELETE | Deactivate or remove resources |
Wrap Paystack calls in try/catch and handle the PaystackError class:
import { paystackRequest, PaystackError } from "@/lib/paystack";
try {
const result = await paystackRequest<Transaction>("/transaction/verify/ref_123");
} catch (error) {
if (error instanceof PaystackError) {
console.error(`Paystack error ${error.statusCode}: ${error.message}`);
// Handle specific status codes
if (error.statusCode === 400) { /* bad request / validation error */ }
if (error.statusCode === 401) { /* invalid secret key */ }
if (error.statusCode === 404) { /* resource not found */ }
}
throw error;
}
PAYSTACK_SECRET_KEY in environment variables only, never in code.env and .env.local to .gitignoredevelopment
Paystack webhook integration — signature validation with HMAC SHA512, event parsing, IP whitelisting, retry policy, and all supported event types. Use this skill whenever setting up a webhook endpoint for Paystack, validating x-paystack-signature headers, handling charge.success or transfer.success events, debugging webhook delivery failures, implementing idempotent event processing, or building any server-side Paystack event listener. Also use when encountering webhook timeout issues or needing the list of Paystack webhook IP addresses.
tools
Paystack Verification API — KYC verification tools for resolving bank accounts, validating account ownership, and looking up card BIN information. Use this skill whenever verifying bank account details before transfers, confirming account holder names, validating customer identity for compliance, looking up card brand/type/bank from BIN, or implementing KYC flows. Also use when you see references to /bank/resolve, /bank/validate, /decision/bin endpoints, or need to match account numbers to names.
development
Paystack Transfers API — send money to bank accounts and mobile wallets. Initiate single and bulk transfers, finalize OTP-verified transfers, list, fetch, and verify transfer status. Use this skill whenever implementing payouts, disbursements, vendor payments, withdrawal flows, or any feature that sends money from your Paystack balance to recipients. Also use when you see references to transfer_code, TRF_ prefixed codes, the /transfer endpoint, or need to handle transfer OTP verification.
development
Paystack Transfer Recipients API — create, list, fetch, update, and delete transfer recipients (beneficiaries) for payouts. Supports NUBAN (Nigeria), GHIPSS (Ghana), Mobile Money, BASA (South Africa), and authorization-based recipients. Use this skill whenever adding bank accounts or mobile wallets as payout destinations, creating transfer recipients before initiating transfers, managing beneficiary lists, or doing bulk recipient creation. Also use when you see references to recipient_code, RCP_ prefixed codes, or the /transferrecipient endpoint.