paystack-setup

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Paystack Setup

Paystack 环境搭建

Set up the foundational Paystack API client and environment configuration for TypeScript/JavaScript server-side applications.
为TypeScript/JavaScript服务端应用搭建Paystack API客户端及环境配置的基础框架。

API Fundamentals

API 基础信息

PropertyValue
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 UnitSubunit of currency (multiply display amount × 100)
Transaction IDUnsigned 64-bit integer — use
string
in TypeScript
属性
基础URL
https://api.paystack.co
认证请求头
Authorization: Bearer SECRET_KEY
内容类型
application/json
响应格式
{ status: boolean, message: string, data: object }
金额单位货币的Subunit(将显示金额 × 100)
交易ID无符号64位整数 — 在TypeScript中使用
string
类型

Supported Currencies & Subunits

支持的货币及Subunit

CurrencyCodeSubunitMultiplier
Nigerian NairaNGNkobo×100
US DollarUSDcent×100
Ghanaian CediGHSpesewa×100
South African RandZARcent×100
Kenyan ShillingKEScent×100
West African CFAXOF×100
Egyptian PoundEGPpiaster×100
Rwandan FrancRWF×100
货币代码Subunit转换乘数
尼日利亚奈拉NGNkobo×100
美元USDcent×100
加纳塞地GHSpesewa×100
南非兰特ZARcent×100
肯尼亚先令KEScent×100
西非金融共同体法郎XOF×100
埃及镑EGPpiaster×100
卢旺达法郎RWF×100

Environment Variables

环境变量

Create a
.env
file (or
.env.local
for Next.js):
env
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.
创建
.env
文件(Next.js项目使用
.env.local
):
env
PAYSTACK_SECRET_KEY=sk_test_xxxxx        # 仅用于服务端,绝不可暴露给客户端
NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY=pk_test_xxxxx  # 可安全用于客户端(Popup/InlineJS)
密钥(
sk_*
)绝不能出现在客户端代码、浏览器打包文件或公开代码仓库中。公钥(
pk_*
)仅可安全用于前端的Paystack Popup/InlineJS功能。
测试密钥以
sk_test_
/
pk_test_
开头,正式密钥以
sk_live_
/
pk_live_
开头。可在Paystack控制台的“设置 → API密钥与Webhooks”中获取。

Install Dependencies

安装依赖

bash
undefined
bash
undefined

For client-side Popup/InlineJS checkout

用于客户端Popup/InlineJS结账功能

npm install @paystack/inline-js
npm install @paystack/inline-js

Or with pnpm / yarn

或使用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.
pnpm add @paystack/inline-js yarn add @paystack/inline-js

无需安装服务端SDK — 使用内置的`fetch` API结合下方的辅助工具即可。

TypeScript API Client Helper

TypeScript API客户端辅助工具

Create a reusable, type-safe Paystack client. Every other Paystack skill depends on this pattern:
typescript
// 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>;
}
创建一个可复用、类型安全的Paystack客户端。所有其他Paystack技能均依赖此模式:
typescript
// 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>;
}

Pagination

分页机制

All list endpoints accept
perPage
(default: 50, max: 100) and
page
(default: 1) as query parameters. The response includes a
meta
object:
json
{
  "meta": {
    "total": 243,
    "skipped": 0,
    "perPage": 50,
    "page": 1,
    "pageCount": 5
  }
}
Build paginated queries like so:
typescript
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}`);
所有列表接口均接受
perPage
(默认值:50,最大值:100)和
page
(默认值:1)作为查询参数。响应结果包含一个
meta
对象:
json
{
  "meta": {
    "total": 243,
    "skipped": 0,
    "perPage": 50,
    "page": 1,
    "pageCount": 5
  }
}
可按如下方式构建分页查询:
typescript
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}`);

Amount Conversion

金额转换

Always convert display amounts to subunits before sending to Paystack, and convert back when displaying:
typescript
// 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
.
在向Paystack发送金额前,务必将显示金额转换为subunit,显示时再转换回来:
typescript
// 显示金额 → Paystack格式(乘以100)
const amountInKobo = Math.round(amountInNaira * 100);

// Paystack格式 → 显示金额(除以100)
const amountInNaira = amountInKobo / 100;
使用
Math.round()
避免浮点数问题,例如
19.99 * 100 = 1998.9999999999998

HTTP Methods

HTTP方法

MethodUsage
POSTCreate resources, initiate actions
GETFetch, list, verify resources
PUTUpdate resources
DELETEDeactivate or remove resources
方法用途
POST创建资源、发起操作
GET获取、列出、验证资源
PUT更新资源
DELETE停用或删除资源

Error Handling

错误处理

Wrap Paystack calls in try/catch and handle the
PaystackError
class:
typescript
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调用包裹在try/catch中,并处理
PaystackError
类:
typescript
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}`);
    // 处理特定状态码
    if (error.statusCode === 400) { /* 请求无效 / 验证错误 */ }
    if (error.statusCode === 401) { /* 密钥无效 */ }
    if (error.statusCode === 404) { /* 资源未找到 */ }
  }
  throw error;
}

Security Checklist

安全检查清单

  • Store
    PAYSTACK_SECRET_KEY
    in environment variables only, never in code
  • Add
    .env
    and
    .env.local
    to
    .gitignore
  • All Paystack API calls must run server-side (API routes, server actions, backend)
  • Use HTTPS for all callback and webhook URLs
  • Validate amounts server-side before initializing transactions
  • Always verify transaction status server-side after payment, never trust client-side callbacks alone
  • 仅将
    PAYSTACK_SECRET_KEY
    存储在环境变量中,绝不要写入代码
  • .env
    .env.local
    添加到
    .gitignore
  • 所有Paystack API调用必须在服务端运行(API路由、服务端操作、后端)
  • 所有回调和Webhook URL均使用HTTPS
  • 在初始化交易前,在服务端验证金额
  • 支付完成后,务必在服务端验证交易状态,绝不要仅信任客户端回调