Skip to content

fintech-sdk/paysafe-sdk

Repository files navigation

paysafe-sdk

Production-grade TypeScript SDK for the Paysafe API.

npm version License: MIT

Coverage

Bounded context Resources
Payments Payment Handles, Payments, Settlements, Refunds, Payouts (standalone & original credits), Verifications
Customer Vault Customer profiles, saved payment handles, single-use customer tokens
Payment Scheduler Plans, Subscriptions (create, update, cancel, suspend, reactivate)
Applications Merchant onboarding: create, update, submit, terms & conditions, document upload
Value Added Services FX Rates, Customer Identity (KYC), Bank Account Validation, Interac Verification (VerifiedMe)
Webhooks HMAC-SHA256 signature verification (constant-time) and event parsing

Install

npm install paysafe-sdk

Requires Node.js >= 18. Also runs on any runtime with fetch and either node:crypto or Web Crypto (SubtleCrypto) — browsers, Deno, Cloudflare Workers, and other edge runtimes.

Quick start

import { PaysafeClient } from "paysafe-sdk";

const client = new PaysafeClient({
  username: process.env.PAYSAFE_USERNAME!,
  password: process.env.PAYSAFE_PASSWORD!,
  environment: "test", // or "production"
  accountId: process.env.PAYSAFE_ACCOUNT_ID!,
});

// 1. Tokenize a card into a Payment Handle.
const handle = await client.paymentHandles.create({
  merchantRefNum: "order-1",
  amount: 5000, // minor currency units — $50.00
  currencyCode: "USD",
  paymentType: "CARD",
  transactionType: "PAYMENT",
  card: {
    cardNum: "4111111111111111",
    cardExpiry: { month: 12, year: 2030 },
    cvv: "123",
    holderName: "Jane Doe",
  },
});

// 2. Charge it.
const payment = await client.payments.create({
  merchantRefNum: "order-1",
  amount: 5000,
  currencyCode: "USD",
  paymentHandleToken: handle.paymentHandleToken,
  settleWithAuth: true,
});

console.log(payment.status); // "COMPLETED"

Or build a client from PAYSAFE_USERNAME / PAYSAFE_PASSWORD / PAYSAFE_ENVIRONMENT / PAYSAFE_ACCOUNT_ID environment variables:

const client = PaysafeClient.fromEnv();

See examples/ for a full payment flow, a subscription signup flow, and a webhook receiver.

Error handling

Every rejected promise from this SDK rejects with a PaysafeError — never a bare string or plain object:

import { PaysafeError } from "paysafe-sdk";

try {
  await client.payments.create(req);
} catch (err) {
  if (err instanceof PaysafeError) {
    console.error(err.kind);       // "api_error" | "http_error" | "rate_limited" | "timeout" | ...
    console.error(err.code);       // Paysafe error code, e.g. "5068"
    console.error(err.httpStatus); // e.g. 400
    console.error(err.fieldErrors); // [{ field: "card.cardNum", error: "Invalid card number" }]
    console.error(err.retryable);  // whether the SDK's own retry policy would retry this
  }
}

Webhooks

import { WebhooksResource, webhookTopic, PaysafeError } from "paysafe-sdk";

const webhooks = new WebhooksResource();

// In your HTTP handler, using the *raw* request body:
try {
  const event = await webhooks.verifyAndParse(rawBody, req.headers["signature"], hmacKey);
  switch (webhookTopic(event)) {
    case "payment_handle":
      // ...
      break;
    // ...
  }
  res.status(200).send("OK");
} catch (err) {
  if (err instanceof PaysafeError && err.kind === "webhook_signature_mismatch") {
    res.status(401).send("Invalid signature");
  }
}

Signature verification uses a constant-time comparison and works identically on Node.js (node:crypto) and Web Crypto runtimes (browsers, Deno, Cloudflare Workers).

Configuration reference

new PaysafeClient({
  username: string,               // required
  password: string,                // required
  environment?: "test" | "production", // default: "test"
  accountId?: string,               // default account ID for resources that need one
  baseUrlOverride?: string,         // override the base URL entirely (e.g. for a mock server in tests)
  timeoutMs?: number,               // per-request timeout, default 30_000
  maxRetries?: number,              // default 3
  retryBaseDelayMs?: number,        // exponential backoff base delay, default 500
  rateLimit?: { limit: number; windowMs: number }, // local token bucket, default 100 req / 1000ms
  fetch?: (url, init) => Promise<Response>, // custom fetch implementation
  telemetryPrefix?: string,         // metric/event name prefix, default "paysafe"
});

Pass a TelemetryHook as the second constructor argument to observe every request:

const client = new PaysafeClient(options, {
  onStart: (meta) => metrics.increment(`${meta.prefix}.${meta.api}.start`),
  onStop: (meta) => metrics.timing(`${meta.prefix}.${meta.api}.duration`, meta.durationMs),
});

Design principles

  • Zero runtime dependencies. Built entirely on platform fetch and crypto APIs.
  • Dual ESM/CJS build with full TypeScript declarations, via tsup.
  • Retry with exponential backoff + jitter on transient failures (5xx, 429, timeouts, and a documented set of Paysafe API error codes).
  • Token-bucket rate limiting per credential, enforced client-side before any network call.
  • Structured errors. Every failure mode maps to a typed PaysafeError.kind.
  • Strict TypeScript: strict, noUncheckedIndexedAccess, and friends are all on.
  • Every resource method accepts an optional AbortSignal for cancellation, composed with the client's own timeout.

Development

npm install
npm run build       # tsup -> dist/ (ESM + CJS + .d.ts)
npm run test         # vitest
npm run lint         # eslint
npm run typecheck    # tsc --noEmit
npm run format       # prettier --write

License

MIT

About

Production-grade TypeScript SDK for the Paysafe API.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors