PayweavePayweave
Open source · payweave@0.1.0 · MIT

One SDK. Every provider. Woven together.

Stripe, Paystack, and Flutterwave behind one typed client — with subscriptions, metered usage, a database layer, and a CLI built in, not bolted on.

$npm install payweave
checkout.ts
import { createPayweave } from "payweave"const payweave = createPayweave({  paystack: { secretKey: process.env.PAYSTACK_SECRET_KEY! },})// One unified call — always minor units; the adapter converts.const checkout = await payweave.checkout.create({  amount: { value: 500_000, currency: "NGN" },  customer: { email: "ada@example.com" },  reference: "order_8123",  redirectUrl: "https://app.example.com/pay/callback",})console.log(checkout.checkoutUrl)
The problem

Wiring up payments usually means doing it three times.

  • Hand-rolling fetch calls against each provider's own REST docs, one provider at a time.
  • Copy-pasting webhook verification snippets — and frequently getting signature validation wrong.
  • Writing your own subscription/plan bookkeeping and database schema by hand.
  • Doing it all again the moment you add a second provider, a database, or usage-based billing.
Three threads, one client

Shipping now, expanding fast

Stripe, Paystack, and Flutterwave v3 — provider-native resources, webhooks, and the unified layer — are implemented and tested. Flutterwave v4's resource surface is next.

Stripe

Shipped

Checkout Sessions, Payment Intents, customers, products & prices, subscriptions, refunds — typed 1:1 from the official API.

Paystack

Shipped

Transactions, refunds, customers, transfers, plans & subscriptions, account verification — typed 1:1 from the official API.

Flutterwave

v3 shipped · v4 in progress

v3 ships payments, transactions, refunds, transfers, banks, and charges. v4's OAuth auth and webhook verifier are in place; its resource surface is next.

What you get

The SDK fundamentals, done once, done right

Full endpoint coverage per provider, fully typed, with first-class webhook verification and a normalized layer when you want portability.

One client, every provider

Configure one or more of Stripe, Paystack, and Flutterwave under createPayweave and get a single, fully-typed client — no hand-rolled fetch calls.

Compile-time provider narrowing

Only configured providers appear on the client. Autocomplete never shows a namespace you didn't set up.

Webhooks, done correctly

One endpoint verifies every configured provider — raw bytes, constant-time comparison, fail-closed — then returns a typed, normalized event.

A capability-gated unified layer

Checkout, verify, refunds, transfers and banks, normalized across providers — gated by a capability matrix, so an unsupported call fails before it's sent, not after.

Errors that name the culprit

Typed subclasses tell you whether a failure is yours (validation/auth), the customer's (declined), or transient (network/5xx).

Money that can't drift

Always integer minor units in the unified layer; the adapters convert kobo, naira, and cents so you never fat-finger a decimal.

Two surfaces, no compromise

Provider-native when you need control. Unified when you want portability.

  • Surface A exposes every endpoint 1:1 with the provider's own field names.
  • Surface B normalizes the high-traffic operations across providers that support them.
  • Every response carries raw, so the abstraction never traps you.
surface-a.ts
// Surface A — every provider endpoint, 1:1 and fully typed.const tx = await payweave.paystack.transactions.initialize({  email: "ada@example.com",  amount: 500_000, // kobo  currency: "NGN",})// The provider is narrowed at compile time:// payweave.flutterwave  ->  not configured on this client
webhook.ts
// One endpoint verifies every configured provider — the header says which.app.post("/webhooks", express.raw({ type: "*/*" }), (req, res) => {  const event = payweave.webhooks.constructEvent({    rawBody: req.body,    headers: req.headers,  })  res.sendStatus(200) // ack fast, process async  switch (event.unifiedType) {    case "payment.succeeded":      // re-verify before granting value      break  }})
Beyond payments

A billing platform, not just an API client

Persist state, define pricing, meter usage, and manage it all from a CLI — without reaching for a separate billing service.

Who it's for

Built for everyone shipping payments

First-time integrators

Accept a payment without reading raw REST docs — initialize one client with a provider and a secret key.

Multi-provider teams

Add a second provider for redundancy or reach behind one normalized layer, so your business logic never branches on provider.

Teams that bill on usage

Plans, features, and metered usage backed by your own database — not a separate billing service to keep in sync.

AI coding agents

Generate integration code against a well-typed, well-documented surface with predictable, discoverable APIs.

Ship your first verified payment in under 10 minutes

Install once, configure a provider, and go from a checkout URL to a verified payment to a handled webhook.