awesome-node-checkout
v1.0.2
Published
Framework-agnostic payment checkout library for Node.js
Maintainers
Readme
awesome-node-checkout
A framework-agnostic payment checkout library for Node.js, written in TypeScript.
Drop-in payment orchestration for Express, NestJS, Fastify and any other Node.js framework — connect any payment provider through a single interface.
Inspired by awesome-node-auth. Same philosophy: no framework lock-in, no DB lock-in, implement one interface and you're done.
Installation
npm install awesome-node-checkoutQuick Start
import { CheckoutConfigurator, PayPalProvider, NexiProvider, SatispayProvider } from 'awesome-node-checkout';
import * as fs from 'fs';
const checkout = new CheckoutConfigurator();
checkout
.registerProvider(new PayPalProvider({
clientId: process.env.PAYPAL_CLIENT_ID!,
clientSecret: process.env.PAYPAL_CLIENT_SECRET!,
environment: 'sandbox',
}))
.registerProvider(new NexiProvider({
merchantId: process.env.NEXI_MERCHANT_ID!,
macKey: process.env.NEXI_MAC_KEY!,
environment: 'sandbox',
}))
.registerProvider(new SatispayProvider({
keyId: process.env.SATISPAY_KEY_ID!,
privateKey: fs.readFileSync('private.pem', 'utf8'),
environment: 'sandbox',
serverUrl: 'https://myapp.com',
}));
// Use directly — no HTTP framework needed
const result = await checkout.createPayment('paypal', {
amount: 49.99,
currency: 'EUR',
description: 'Order #1234',
returnUrl: 'https://myapp.com/payment/success',
cancelUrl: 'https://myapp.com/payment/cancel',
orderId: 'ORD-1234',
});
if (result.approvalUrl) {
// redirect the user to result.approvalUrl
}With Express adapter
import express from 'express';
import { createCheckoutRouter } from 'awesome-node-checkout/express';
const app = express();
app.use(express.json());
// Mounts all checkout routes under /checkout
app.use('/checkout', createCheckoutRouter(checkout));
app.listen(3000);With Fastify (or any other framework)
Use the CheckoutConfigurator methods directly in your own routes:
fastify.post('/checkout/:provider', async (req, reply) => {
const result = await checkout.createPayment(req.params.provider, req.body);
reply.status(result.success ? 201 : 400).send(result);
});
fastify.post('/checkout/:provider/webhook', async (req, reply) => {
const result = await checkout.handleWebhook(req.params.provider, req.body, req.headers);
reply.send(result);
});Routes (Express adapter)
| Method | Path | Description |
|--------|-----------------------------|----------------------------------|
| POST | /:provider | Create a payment |
| POST | /:provider/execute | Execute/capture a payment |
| GET | /:provider/redirect | Handle provider redirect callback|
| GET | /:provider/:id | Get payment details |
| POST | /:provider/refund | Refund a payment |
| POST | /:provider/webhook | Handle provider webhook |
Payment Flows
| Flow | Providers | Description |
|------------|------------------|----------------------------------------------------------|
| redirect | PayPal, Nexi | User is redirected to provider, returns with query params|
| webhook | Satispay | Provider calls a webhook URL after async confirmation |
| direct | (future) | Synchronous processing (card tokenization, etc.) |
Events
checkout.events
.on('payment.created', ({ provider, paymentId }) => { /* ... */ })
.on('payment.completed', ({ provider, paymentId }) => { /* ... */ })
.on('payment.failed', ({ provider, error }) => { /* ... */ })
.on('payment.refunded', ({ provider, paymentId }) => { /* ... */ })
.on('webhook.received', ({ provider, data }) => { /* ... */ });Custom Transaction Store
By default, SatispayProvider uses an in-memory store to correlate webhooks with orders.
For multi-instance deployments, implement ITransactionStore:
import { ITransactionStore, TransactionData } from 'awesome-node-checkout';
class RedisTransactionStore implements ITransactionStore {
async save(key: string, data: TransactionData): Promise<void> { /* ... */ }
async get(key: string): Promise<TransactionData | null> { /* ... */ }
async delete(key: string): Promise<void> { /* ... */ }
}
new SatispayProvider({
keyId: '...',
privateKey: '...',
transactionStore: new RedisTransactionStore(),
});Custom Provider
Extend BasePaymentProvider to add any payment provider:
import { BasePaymentProvider, PaymentRequest, PaymentResult } from 'awesome-node-checkout';
export class StripeProvider extends BasePaymentProvider {
readonly name = 'stripe';
readonly flow = 'redirect' as const;
async createPayment(request: PaymentRequest): Promise<PaymentResult> {
// ... call Stripe API
}
// ... implement other methods
async handleRedirect(query: Record<string, any>): Promise<PaymentResult> {
// ... handle Stripe redirect
}
}
checkout.registerProvider(new StripeProvider({ secretKey: '...' }));Built-in Providers
| Provider | Flow | Notes | |-----------|-----------|--------------------------------------------| | PayPal | redirect | Orders API v2 | | Nexi | redirect | eCommerce DispatcherServlet + MAC SHA-1 | | Satispay | webhook | Business API v1, RSA-SHA256 signature |
License
MIT
