One payment interface. Any provider.
A strongly typed TypeScript runtime for composing payment providers while keeping routing, persistence, orders, and settlement in your application.
npm i @payments-sdk/payments
import { createPayments } from "@payments-sdk/payments";
import { fonepay } from "@payments-sdk/fonepay";
import { esewa } from "@payments-sdk/esewa";
const payments = createPayments({
providers: [
fonepay({ ... }),
esewa({ ... }),
],
});
const checkout = await payments.checkout({
provider: "fonepay",
amount: 1500_00,
currency: "NPR",
reference: "order_123",
providerOptions: { ... },
});- runtime
- TypeScript / ESM
- providers
- independently installed
- ownership
- your application
Providers stay outside the runtime.
@payments-sdk/payments is provider-neutral. Install the gateways your application needs, pass them to createPayments(), and the configured runtime shapes from there. Provider packages can evolve independently — adding one changes the inferred API surface.
createPayments(...)@payments-sdk/payments@payments-sdk/fonepay@payments-sdk/esewa@payments-sdk/khaltiThe configured surface is the API.
Provider IDs, checkout options, result types, webhook namespaces, and capabilities are inferred from the providers passed to createPayments(). Nothing is guessable — the type system enforces what the configuration permits.
- provider IDs
- from the configured array
- options and results
- narrowed per provider
- capabilities
- present when supported
const checkout = await payments.checkout({
provider: "fonepay",
// providerOptions is FonepayCheckoutOptions
});
payments.returns.esewa;
payments.webhooks.fonepay;
// only exists when supported and configuredDifferent gateways. Predictable next steps.
Normalization does not erase provider behavior. Each gateway keeps the protocol it actually needs — QR payload, form POST, or redirect — while your application receives a typed action it can handle consistently.
QR payloadDynamic QR checkoutcheckout.actiondisplay_qrForm POSTePay v2 checkoutcheckout.actionsubmit_formRedirectKPG-2 checkoutcheckout.actionredirectYour application owns the transaction.
Payments SDK gives your application typed payment primitives and leaves the rest of your architecture where it belongs.
There is no HTTP router, database, order system, settlement workflow, retry policy, or fulfillment logic inside the runtime. Those stay in your application, designed the way your product needs them.
before · shape or inspect inputafter · observe the typed resulterror · handle provider failures
@payments-sdk/paymentstyped payment primitivesprovider adaptersgateway-specific behaviorOpen provider protocol.
Providers implement an open protocol. First-party and third-party packages use the same contract — your application only installs what it needs, and the main runtime stays provider-neutral.
Lifecycle hooks let you observe operations without moving application concerns into the SDK. Logging, telemetry, policy checks, and persistence integration stay at your payment boundary.
const payments = createPayments({
providers: [fonepay({ ... })],
hooks: {
checkout: {
before: async ({ input, provider }) => {},
after: async ({ result, provider }) => {},
error: async ({ error, provider }) => {},
},
},
});Build your payment boundary.
Start with the provider protocol, then keep the application architecture that matters to you.