A production-grade, independent TypeScript client for the Increase API — banking-as-a-service for accounts, ACH/wire/check/RTP/FedNow transfers, cards, entities, and more.
Covers Increase's full API surface (~90 resource groups, ~240 operations). Zero runtime dependencies — built entirely on the platform fetch, Headers, AbortController, and Web Crypto APIs, so it runs unmodified on Node ≥18, Deno, Bun, Cloudflare Workers, and in the browser.
npm install increase-sdkimport { Increase } from "increase-sdk";
const client = new Increase({
apiKey: process.env.INCREASE_API_KEY,
environment: "sandbox", // or "production"
});
const account = await client.accounts.create({ name: "My First Account" });
console.log(account.id);
// Lazy, cursor-based pagination -- pages are fetched on demand as you
// iterate, not all up front.
for await (const account of await client.accounts.list()) {
console.log(account.id, account.name);
}
// Sandbox-only simulations let you drive objects through their
// lifecycle without waiting on real banking rails.
const transfer = await client.achTransfers.create({
account_id: account.id,
amount: 1000,
statement_descriptor: "Test payment",
});
await client.simulations.achTransfers.submit(transfer.id);import { IncreaseError } from "increase-sdk";
try {
await client.accounts.retrieve("account_does_not_exist");
} catch (err) {
if (err instanceof IncreaseError) {
console.log(err.status, err.type, err.detail);
if (err.isNotFound) {
// ...
}
}
}import { verifyWebhookSignature } from "increase-sdk";
// Express/Node example -- use whatever gives you the *raw* request body.
app.post("/webhooks/increase", express.text({ type: "*/*" }), async (req, res) => {
try {
await verifyWebhookSignature(req.body, req.headers, signingSecret);
} catch {
return res.status(400).send("invalid signature");
}
const event: unknown = JSON.parse(req.body);
res.status(200).end();
});maxRetries (default 2) retries rate-limited (429) and server-error (5xx/408/409) responses with exponential backoff and jitter, honoring Retry-After when present. Because retrying a POST/PATCH naively could double-create something, the transport generates an Idempotency-Key once before the first attempt and reuses it across every retry of that request — Increase guarantees replaying the same key returns the original result.
Every method accepts a trailing options object for one-off overrides:
await client.accounts.create(
{ name: "My Account" },
{ idempotencyKey: "my-own-key", timeoutMs: 10_000, signal: myAbortSignal },
);const client = new Increase({
apiKey,
logger: (event) => console.log(event.type, event),
});Emits structured events for request start, completion (status, duration, attempt count), retries, and terminal failures.
increase-sdk/
├── src/
│ ├── index.ts Package entry point (re-exports everything below)
│ ├── client.ts The Increase client class, wiring every resource
│ ├── version.ts
│ ├── core/
│ │ ├── request.ts Transport: fetch + retries + idempotency + logging
│ │ ├── pagination.ts Generic, lazy, async-iterable Page<T>
│ │ ├── resource.ts BaseResource every generated resource extends
│ │ ├── error.ts IncreaseError / IncreaseConnectionError
│ │ ├── webhook.ts Standard Webhooks signature verification
│ │ └── qs.ts Query parameter encoding
│ └── resources/ One file per resource: types + a *Resource class
│ (account.ts, ach-transfer.ts, card.ts, ...)
└── test/ Vitest suite: transport, pagination, webhook,
error decoding, and end-to-end client tests
- Field names match the wire format (
created_at,account_id, notcreatedAt/accountId) rather than being converted to camelCase — the same convention Stripe's, OpenAI's, and Anthropic's own TypeScript SDKs use. This means there's no naming-translation layer that could introduce bugs or drift from Increase's own API documentation; what you see in the docs is exactly what you type. - Enums are string-literal unions (
"open" | "closed"), not runtime enum objects, matching modern TypeScript convention and keeping the compiled output small. - Nullable response fields are typed
T | null; optional request parameters arefield?: T. - Pagination: every
list()method returns aPromise<Page<T>>.PageimplementsAsyncIterable, sofor await (const item of await resource.list())walks every item across every page, fetching each subsequent page only when the current one is exhausted. - File uploads:
client.files.createis the one method that sendsmultipart/form-data(via the platformFormData) instead of JSON, since it uploads raw bytes. Its response type is namedIncreaseFilerather thanFileto avoid shadowing the platform's built-inFile/Blob API type.
Domain models and endpoint definitions were derived from Increase's published API surface (cross-referenced against Increase's official Go SDK for field-level accuracy) and reimplemented from scratch as an independent, generated TypeScript client — not a fork or a port of any existing package.
npm run build # tsup -> dist/ (ESM + CJS + .d.ts)
npm run typecheck # tsc --noEmit
npm run lint # eslint .
npm run format:check # prettier --check .
npm test # vitest run
npm run test:coverage # vitest run --coverage