Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

payments-integration-kit

Provider-agnostic TypeScript building blocks for reliable payment integrations. Patterns extracted from years of shipping fintech systems — without coupling to any specific PSP.

What's in the box

  • IdempotencywithIdempotency() wrapper + pluggable store interface so retried client requests never double-charge.
  • Double-entry ledger — minimal in-memory Ledger that enforces debits == credits at post time. Use it directly, or as a reference shape for your persistent ledger.
  • Webhook signature verification — HMAC-SHA256 verifier with timestamp tolerance and constant-time comparison. Compatible with the signing scheme most providers use (Stripe-style t=...,v1=...).

No provider SDKs. No HTTP framework. Just patterns you compose into your own service.

Install

npm install
npm test
npm run example

Quick example

import { InMemoryIdempotencyStore, withIdempotency, Ledger } from "payments-integration-kit";

const store = new InMemoryIdempotencyStore<{ chargeId: string }>();
const ledger = new Ledger();

const result = await withIdempotency(store, idempotencyKey, fingerprint, async () => {
  ledger.post({
    id: "ch_001",
    currency: "ZMW",
    entries: [
      { account: "customer:123", direction: "debit",  amount: 5000n },
      { account: "revenue",       direction: "credit", amount: 5000n },
    ],
  });
  return { chargeId: "ch_001" };
});

See examples/charge-flow.ts for an end-to-end flow combining all three primitives.

Design notes

  • bigint for money. No floats anywhere. Amounts are minor units (ngwee, cents). Currency is tracked separately and never mixed.
  • Idempotency stores its result, not just its key. Replays return the original response — that is the entire point of the pattern.
  • Fingerprints catch key reuse. If the same key arrives with a different body, you get a conflict instead of silently returning a stale result.
  • Webhook verification rejects on time skew. A valid signature on a 6-hour-old payload is still a replay attack.

Status

v0.1 — minimal but real. Roadmap:

  • Reconciliation helpers (compare provider settlements vs. ledger)
  • Retry policy primitive (exponential backoff with jitter, dead-letter)
  • Persistent store adapters (Postgres, Redis)
  • Money type with currency-safe arithmetic

License

MIT © Penjani Mkandawire

About

Provider-agnostic TypeScript building blocks for reliable payment integrations: idempotency, double-entry ledger, webhook signature verification.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages