Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
600f073
feat: complete transactions and customers resources with auto-paginat…
samaasi Jun 17, 2026
14ed88e
fix: RequestExecutor type signature and apply to ApplePay
samaasi Jun 17, 2026
fb5577e
Add backward compatibility for transactions.requery() and expand webh…
samaasi Jun 17, 2026
d717dbb
Fix TypeScript errors in integration files
samaasi Jun 17, 2026
7728015
Fix remaining TypeScript error in nestjs.ts
samaasi Jun 17, 2026
8931088
Complete Paystack SDK V1 implementation
samaasi Jun 17, 2026
e130185
Update README with new features
samaasi Jun 17, 2026
f785ea7
feat: implement Paystack API resources and configure CI pipeline
samaasi Jun 18, 2026
5c66e2c
feat: implement Paystack resources including bulk charges, splits, vi…
samaasi Jun 18, 2026
a17919e
feat: implement Fastify webhook verification and add support for disp…
samaasi Jun 18, 2026
446d135
feat: add resources for products, virtual accounts, disputes, payment…
samaasi Jun 18, 2026
b2d0d1e
feat: implement resource modules and add comprehensive webhook verifi…
samaasi Jun 18, 2026
d57f70e
feat: implement resource modules for products, disputes, transfers, p…
samaasi Jun 18, 2026
c14819b
feat: implement resource classes and types for virtual accounts, tran…
samaasi Jun 18, 2026
366e56b
feat: add resources for splits, transfers, recipients, products, sett…
samaasi Jun 18, 2026
796d748
feat: implement resources for plans, splits, virtual accounts, transf…
samaasi Jun 18, 2026
c8caf5a
feat: implement resources for transfer recipients, plans, settlements…
samaasi Jun 18, 2026
94b563d
feat: implement resources for plans, splits, and virtual accounts, an…
samaasi Jun 18, 2026
4678557
feat: implement resources for Splits, Virtual Accounts, and Plans, al…
samaasi Jun 18, 2026
be382b4
feat: add Plans resource, define Dispute types, and implement webhook…
samaasi Jun 18, 2026
a936485
test: add comprehensive unit tests for webhook verification and frame…
samaasi Jun 18, 2026
cd4cfb5
feat: add Subscriptions and Verification resources and Express/NestJS…
samaasi Jun 18, 2026
6f5e7ea
feat: implement Subscriptions and Verification resources, and add Fas…
samaasi Jun 18, 2026
2344916
feat: add NestJS webhook guard and implement Subscriptions and Misc A…
samaasi Jun 18, 2026
8885d1c
feat: implement misc, verification, and subscription resources with a…
samaasi Jun 18, 2026
1cb11eb
feat: add Misc and Verification resource modules with corresponding u…
samaasi Jun 18, 2026
18a074e
feat: add verification resource and implement comprehensive SDK resou…
samaasi Jun 18, 2026
9df20b6
feat: implement verification resource for account and BVN resolution …
samaasi Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
- name: Install dependencies
run: bun install

- name: Type Check
run: bunx tsc --noEmit

- name: Lint
run: bun run lint

Expand Down
21 changes: 15 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,39 @@ This project uses **[Bun](https://bun.sh/)** as the package manager and test run
## 💻 Development Workflow

### Building the SDK

To build the project (using `tsup`):

```bash
bun run build
```

To run the build in watch mode during development:

```bash
bun run dev
```

### Running Tests

We use **Bun's built-in test runner**.

```bash
bun test
```

### Formatting & Linting

We use **Prettier** for formatting and **ESLint** for linting.

To format your code:

```bash
bun run format
```

To check for linting errors:

```bash
bun run lint
```
Expand All @@ -77,15 +85,16 @@ bun run lint

## 📝 Coding Guidelines

- **Type Safety**: Ensure all new code is fully typed. Avoid using `any` unless absolutely necessary.
- **Documentation**: Add JSDoc comments to new methods and interfaces.
- **Tests**: Write clear and concise unit tests for your logic.
- **Type Safety**: Ensure all new code is fully typed. Avoid using `any` unless absolutely necessary.
- **Documentation**: Add JSDoc comments to new methods and interfaces.
- **Tests**: Write clear and concise unit tests for your logic.

## 🐛 Reporting Bugs

If you find a bug, please open an issue on GitHub with:
- A clear title and description.
- Steps to reproduce the issue.
- Expected vs. actual behavior.

- A clear title and description.
- Steps to reproduce the issue.
- Expected vs. actual behavior.

Thank you for contributing!
117 changes: 99 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ This library targets modern runtimes:
### Create a client

```ts
import { PaystackClient } from 'paystack-sdk'
import { PaystackClient } from 'paystack-sdk-node'

const client = new PaystackClient({
apiKey: process.env.PAYSTACK_SECRET_KEY!,
Expand All @@ -50,11 +50,26 @@ You can optionally override:
- `baseUrl` (defaults to `https://api.paystack.co`)
- `maxRetries` (defaults to `3`)
- `fetchImpl` (custom fetch for environments without global `fetch`)
- `logger` (custom logger to debug API requests/responses)

```ts
import { PaystackClient } from 'paystack-sdk-node'

const client = new PaystackClient({
apiKey: process.env.PAYSTACK_SECRET_KEY!,
logger: {
debug: (msg, data) => console.debug(`[Paystack] ${msg}`, data),
info: (msg, data) => console.info(`[Paystack] ${msg}`, data),
warn: (msg, data) => console.warn(`[Paystack] ${msg}`, data),
error: (msg, data) => console.error(`[Paystack] ${msg}`, data),
},
})
```

You can also create a client from environment variables using `createPaystackClient`, which reads standard config keys from your environment:

```ts
import { createPaystackClient } from '@samaasi/paystack-sdk'
import { createPaystackClient } from 'paystack-sdk-node'

const client = await createPaystackClient()
```
Expand Down Expand Up @@ -95,6 +110,41 @@ const tx = await client.transactions.initialize({

// Verify a transaction
const verified = await client.transactions.verify(tx.data.reference)

// Fetch a transaction
const transaction = await client.transactions.fetch(12345)

// List transactions (with pagination)
const transactions = await client.transactions.list({ perPage: 20, page: 1 })

// List all transactions (with auto-pagination using async iterator)
for await (const tx of client.transactions.listAll()) {
console.log(tx.reference)
}

// Charge authorization
const charged = await client.transactions.chargeAuthorization({
email: 'customer@example.com',
amount: 50000,
authorization_code: 'AUTH_xxxxxxxx',
})

// View transaction timeline
const timeline = await client.transactions.timeline('TXN_xxxxxxxx')

// Get transaction totals
const totals = await client.transactions.totals({ from: '2024-01-01', to: '2024-12-31' })

// Export transactions
const exported = await client.transactions.export({ from: '2024-01-01', to: '2024-12-31' })

// Partial debit
const partialDebit = await client.transactions.partialDebit({
email: 'customer@example.com',
amount: 10000,
authorization_code: 'AUTH_xxxxxxxx',
currency: 'NGN',
})
```

### Apple Pay
Expand All @@ -118,23 +168,32 @@ await client.applePay.unregisterDomain({

### Webhooks

The SDK provides helper functions and an event enum to make handling webhooks type-safe and secure.
The SDK provides helper functions and an exhaustive event enum to make handling webhooks type-safe and secure.

```ts
import { PaystackEvent } from 'paystack-sdk/enums'
import { PaystackEvent } from 'paystack-sdk-node'

// Check if an event string matches a known Paystack event
if (event === PaystackEvent.ChargeSuccess) {
// Handle successful charge
}

// Many more events available:
// - PaystackEvent.ChargePending
// - PaystackEvent.ChargeFailed
// - PaystackEvent.TransferSuccess
// - PaystackEvent.TransferFailed
// - PaystackEvent.SubscriptionCreate
// - PaystackEvent.SubscriptionDisable
// - etc.
```

#### Framework Integrations

**Express**

```ts
import { createPaystackExpressMiddleware } from 'paystack-sdk/express'
import { createPaystackExpressMiddleware } from 'paystack-sdk-node/express'

app.post(
'/webhook',
Expand All @@ -152,7 +211,7 @@ app.post(
**Next.js (App Router)**

```ts
import { verifyPaystackNextjsRequest } from 'paystack-sdk/nextjs'
import { verifyPaystackNextjsRequest } from 'paystack-sdk-node/nextjs'

export async function POST(req: Request) {
const { valid, event } = await verifyPaystackNextjsRequest(req, {
Expand All @@ -169,7 +228,7 @@ export async function POST(req: Request) {
**Fastify**

```ts
import { createPaystackFastifyHook } from 'paystack-sdk/fastify'
import { createPaystackFastifyHook } from 'paystack-sdk-node/fastify'

fastify.post(
'/webhook',
Expand All @@ -186,6 +245,28 @@ fastify.post(
)
```

**NestJS**

```ts
import { Controller, Post, Req, UseGuards } from '@nestjs/common'
import { PaystackWebhookGuard } from 'paystack-sdk-node/nestjs'

@Controller('webhooks/paystack')
@UseGuards(
new PaystackWebhookGuard({
secretKey: process.env.PAYSTACK_SECRET_KEY!,
}),
)
export class PaystackWebhookController {
@Post()
handle(@Req() req: any) {
const event = req.paystackEvent
// handle event
return 'ok'
}
}
```

### Transfers and recipients

```ts
Expand Down Expand Up @@ -262,10 +343,10 @@ The SDK provides low-level signature helpers and some framework-specific utiliti

### Signature verification

Subpath: `paystack-sdk/webhooks`
Subpath: `paystack-sdk-node/webhooks`

```ts
import { verifyPaystackSignature } from 'paystack-sdk/webhooks'
import { verifyPaystackSignature } from 'paystack-sdk-node/webhooks'

const valid = await verifyPaystackSignature({
payload: rawBody, // string or Uint8Array
Expand All @@ -279,7 +360,7 @@ const valid = await verifyPaystackSignature({
Subpath: root resources

```ts
import { isWebhookEvent, type WebhookEvent } from 'paystack-sdk'
import { isWebhookEvent, type WebhookEvent } from 'paystack-sdk-node'

if (isWebhookEvent(body)) {
const event: WebhookEvent = body
Expand All @@ -296,11 +377,11 @@ if (isWebhookEvent(body)) {

### Express

Subpath: `paystack-sdk/express`
Subpath: `paystack-sdk-node/express`

```ts
import express from 'express'
import { createPaystackExpressMiddleware } from 'paystack-sdk/express'
import { createPaystackExpressMiddleware } from 'paystack-sdk-node/express'

const app = express()

Expand All @@ -321,11 +402,11 @@ Ensure your Express setup preserves the raw request body (for example by using a

### NestJS

Subpath: `paystack-sdk/nestjs`
Subpath: `paystack-sdk-node/nestjs`

```ts
import { Controller, Post, Req, UseGuards } from '@nestjs/common'
import { PaystackWebhookGuard } from 'paystack-sdk/nestjs'
import { PaystackWebhookGuard } from 'paystack-sdk-node/nestjs'

@Controller('webhooks/paystack')
@UseGuards(
Expand All @@ -336,7 +417,7 @@ import { PaystackWebhookGuard } from 'paystack-sdk/nestjs'
export class PaystackWebhookController {
@Post()
handle(@Req() req: any) {
const event = req.body
const event = req.paystackEvent
// handle event
return 'ok'
}
Expand All @@ -345,12 +426,12 @@ export class PaystackWebhookController {

### Next.js (App Router)

Subpath: `paystack-sdk/nextjs`
Subpath: `paystack-sdk-node/nextjs`

```ts
// app/api/webhooks/paystack/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { verifyPaystackNextjsRequest } from 'paystack-sdk/nextjs'
import { verifyPaystackNextjsRequest } from 'paystack-sdk-node/nextjs'

export async function POST(req: NextRequest) {
const { valid, event } = await verifyPaystackNextjsRequest(req, {
Expand All @@ -373,7 +454,7 @@ export async function POST(req: NextRequest) {
The SDK includes helpers for idempotent requests via the `x-idempotency-key` header.

```ts
import { generateIdempotencyKey, withIdempotencyKey } from 'paystack-sdk'
import { generateIdempotencyKey, withIdempotencyKey } from 'paystack-sdk-node'

const key = generateIdempotencyKey()

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ We take the security of this SDK seriously. If you discover a security vulnerabi

All security vulnerabilities will be addressed promptly.

Please **do not** disclose security-related issues publicly until we have addressed them.
Please **do not** disclose security-related issues publicly until we have addressed them.
Loading