Surface A — the provider-native, fully-typed layer for Stripe, Paystack, and Flutterwave v3, with Flutterwave v4 in progress.
Surface A exposes every endpoint in each provider's official docs, 1:1, with the provider's own field names and semantics. Configure a provider under createPayweave({...}) and its namespace appears on the client, fully typed; providers you didn't configure aren't there at all.
const payweave = createPayweave({
stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
paystack: { secretKey: process.env.PAYSTACK_SECRET_KEY! },
defaultProvider: "paystack",
})
// Paystack — amounts in kobo (its native minor units)
const tx = await payweave.paystack.transactions.initialize({
email: "ada@example.com",
amount: 500_000, // ₦5,000
currency: "NGN",
})
console.log(tx.authorization_url)
// Stripe — amounts in cents (its native minor units)
const session = await payweave.stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: "price_123", quantity: 1 }],
success_url: "https://app.example.com/success",
})List endpoints expose an async iterator so you can page without bookkeeping:
for await (const t of payweave.paystack.transactions.iterate({ perPage: 100 })) {
// ...
}Typed 1:1 from the Stripe API reference:
checkout.sessions — create, retrieve, list/iterate, expire, lineItems/iterateLineItemspaymentIntents — create, retrieve, confirm, capture, cancel, list/iteratecustomers — create, retrieve, update, delete, list/iterate, search/iterateSearchproducts, prices — create, retrieve, update, list/iterate, search/iterateSearch (prices have no delete endpoint — archive via update({ active: false }))subscriptions — create, retrieve, update, cancel, resume (paused only), list/iteratesubscriptionItems — create, retrieve, update, delete, list/iteraterefunds — create, retrieve, update, cancel, list/iteratewebhookEndpoints — create, retrieve, update, delete, list/iterateConfig: secretKey (sk_/rk_ + _test_/_live_), webhookSecret (whsec_*, required to verify Stripe webhooks), apiVersion (defaults to a pinned version, sent as Stripe-Version on every request), and an optional accountId (acct_*, sent as Stripe-Account for Connect). Requests that mutate state accept an idempotencyKey.
Typed 1:1 from the Paystack API reference:
transactions — initialize, verify, list/iterate, fetch, chargeAuthorization, timeline, totals, partialDebitrefunds — create, list/iterate, fetchcustomers — create, list/iterate, fetch, update, validate, setRiskAction, deactivateAuthorizationtransferRecipients + transfers (initiate, list/iterate, fetch, verify, balance)misc — listBanks, resolveAccountNumber, listCountries, listStates, resolveCardBinplans, subscriptions (create, list/iterate, fetch, enable, disable)Config: just secretKey (sk_test_/sk_live_). Paystack has no separate webhook-signing secret — its HMAC is keyed off the same secretKey.
The default surface when version is omitted:
payments.create — hosted payment linktransactions — verify by id, verify by tx_ref, list/iterate, feesrefunds — create, list/iterate, fetchtransfers + beneficiariesbanks — list by country, branches, resolve accountcharges — card (3DES-encrypted via encryptionKey), bank transfer, USSD, NG account transfer, plus a validate step for OTP/PIN confirmationFlutterwave has no plans/subscriptions resource — build recurring billing with Payweave's own plans & features layer instead. Amounts are major units (naira) here, unconverted.
v4 is a different API generation (OAuth client-credentials auth, new resource ids, restructured payloads) — modeled as its own adapter surface, not a re-skin of v3. Opt in explicitly:
const payweave = createPayweave({
flutterwave: {
version: "v4",
clientId: process.env.FLW_V4_CLIENT_ID!,
clientSecret: process.env.FLW_V4_CLIENT_SECRET!,
},
})OAuth token exchange (cached and refreshed automatically) and the v4 webhook verifier are already in place; the resource surface (charges, customers, refunds, transfers) hasn't landed yet.
v4's API base URL and token endpoint are still unverified placeholders in the current build — don't point this at production traffic yet.
The provider-native surface never blocks you: every unified response also carries the untouched provider payload on raw, and you can always drop down to Surface A for a provider-specific endpoint.