关于 paystack-setup
paystack-setup 是一项技能,帮助 TypeScript/JavaScript 服务端应用配置 Paystack API 客户端与环境变量。它涵盖请求认证、分页、金额子单位换算和密钥安全实践。
主要功能
- 01配置 Paystack API 客户端
- 02管理服务端与公开密钥
- 03处理分页请求
- 04换算金额与货币子单位
- 05处理 API 错误
- 06遵循密钥与交易安全实践
适用场景
- 01在服务端发起 Paystack API 请求
- 02分页读取交易列表
- 03将展示金额转换为子单位
- 04验证交易并处理 API 错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rexedge/ paystack --skill paystack-setup安装后在 Claude Code 中输入/paystack-setup确认已加载。
详细介绍
Paystack 设置
为 TypeScript/JavaScript 服务端应用设置基础的 Paystack API 客户端和环境配置。
API 基础信息
| 属性 | 值 |
|---|---|
| 基础 URL | https://api.paystack.co |
| 身份验证标头 | Authorization: Bearer SECRET_KEY |
| 内容类型 | application/json |
| 响应格式 | { status: boolean, message: string, data: object } |
| 金额单位 | 货币的次级单位(显示金额 × 100) |
| 交易 ID | 无符号 64 位整数——在 TypeScript 中使用 string |
支持的货币和次级单位
| 货币 | 代码 | 次级单位 | 倍数 |
|---|---|---|---|
| 尼日利亚奈拉 | NGN | kobo | ×100 |
| 美元 | USD | cent | ×100 |
| 加纳塞地 | GHS | pesewa | ×100 |
| 南非兰特 | ZAR | cent | ×100 |
| 肯尼亚先令 | KES | cent | ×100 |
| 西非法郎 | XOF | — | ×100 |
| 埃及镑 | EGP | piaster | ×100 |
| 卢旺达法郎 | RWF | — | ×100 |
环境变量
创建 .env 文件(Next.js 项目使用 .env.local):
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)
密钥(sk_*)绝不能出现在客户端代码、浏览器包或公开代码仓库中。公钥(pk_*)仅可安全地用于前端的 Paystack Popup/InlineJS。
测试密钥以 sk_test_ / pk_test_ 开头。正式密钥以 sk_live_ / pk_live_ 开头。请在 Paystack Dashboard 的 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
无需服务端 SDK——使用内置的 fetch API 和下方的辅助函数即可。
TypeScript API 客户端辅助函数
创建一个可复用、类型安全的 Paystack 客户端。所有其他 Paystack 技能都依赖此模式:
// 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>;
}
分页
所有列表端点都接受 perPage(默认值:50,最大值:100)和 page(默认值:1)作为查询参数。响应包含一个 meta 对象:
{
"meta": {
"total": 243,
"skipped": 0,
"perPage": 50,
"page": 1,
"pageCount": 5
}
}
按如下方式构建分页查询:
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}`);
金额转换
发送给 Paystack 前,务必将显示金额转换为次级单位;显示时再转换回来:
// Display → Paystack (multiply by 100)
const amountInKobo = Math.round(amountInNaira * 100);
// Paystack → Display (divide by 100)
const amountInNaira = amountInKobo / 100;
使用 Math.round() 避免浮点数问题,例如 19.99 * 100 = 1998.9999999999998。
HTTP 方法
| 方法 | 用途 |
|---|---|
| POST | 创建资源、发起操作 |
| GET | 获取、列出、验证资源 |
| PUT | 更新资源 |
| DELETE | 停用或移除资源 |
错误处理
使用 try/catch 包装 Paystack 调用,并处理 PaystackError 类:
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,绝不写入代码 - 将
.env和.env.local添加到.gitignore - 所有 Paystack API 调用都必须在服务端运行(API 路由、服务端操作、后端)
- 所有回调和 webhook URL 都必须使用 HTTPS
- 初始化交易前在服务端验证金额
- 付款后务必在服务端验证交易状态,切勿仅信任客户端回调