A production-grade, fully-typed TypeScript SDK for the Weavr Multi embedded banking API — Managed Accounts, Managed Cards, Corporates, Consumers, Transfers, Sends, Bulk processing, Back Office, and more.
Ported from and kept at behavioural parity with weavr-go, the same author's production Go client for the Weavr Multi API.
- Full API coverage — every confirmed Weavr Multi endpoint across 14 resource areas.
- Strict TypeScript — every request/response shape is typed;
strict: true,noUncheckedIndexedAccess, noanyleaking through the public API. - Dual ESM/CJS — works from
importandrequire(), with a single bundled.d.ts. - Zero runtime dependencies — built on the native
fetch,AbortController, andURLAPIs (Node ≥ 18, or any modern runtime/browser). - Automatic retries — exponential backoff with jitter on
429/500/502/503/504, fully configurable. - Idempotency-safe — first-class support for the
idempotency-refheader on every mutating call. - Typed error hierarchy —
WeavrAPIError,WeavrValidationError,WeavrNetworkError,WeavrTimeoutError, each with type guards andWeavrAPIErrorclassification helpers (isNotFound(),isStepUpRequired(), etc.). - Testable by design — inject a custom
fetchfor tests, mocks, or non-standard runtimes. - Tree-shakeable —
sideEffects: false, named exports throughout.
npm install weavr-sdk
# or
pnpm add weavr-sdk
# or
yarn add weavr-sdkRequires Node.js ≥ 18 (for the global fetch/AbortController APIs), or any browser/edge runtime that provides them. On older Node versions, pass your own fetch implementation via the fetch config option (e.g. from undici or node-fetch).
import { WeavrClient } from "weavr-sdk";
const weavr = new WeavrClient({
apiKey: process.env.WEAVR_API_KEY!,
environment: "sandbox", // or "live"
});
// 1. Authenticate
const { token } = await weavr.auth.login({
email: "user@example.com",
password: { value: "hunter2" },
});
// 2. List managed accounts
const { accounts } = await weavr.accounts.list(token, { limit: 25 });
// 3. Create a managed account (requires a stepped-up token in production flows)
const account = await weavr.accounts.create(
token,
{ profileId: "your-profile-id", friendlyName: "Operating Account", currency: "GBP" },
crypto.randomUUID(), // idempotency key
);
console.log(account.id, account.state.state);import { WeavrClient } from "weavr-sdk";
const weavr = new WeavrClient({
apiKey: "YOUR_API_KEY", // required — found in Multi Portal > API Credentials
environment: "sandbox", // "sandbox" (default) | "live"
timeoutMs: 30_000, // per-request timeout, default 30s
retry: {
maxAttempts: 3, // default 3
baseDelayMs: 250, // default 250ms
maxDelayMs: 4_000, // default 4s
retryableStatusCodes: [429, 500, 502, 503, 504],
},
fetch: myCustomFetch, // optional, e.g. for Node < 18 or testing
baseURL: "https://...", // optional override of the Multi API base URL
backOfficeBaseURL: "https://...", // optional override of the Back Office base URL
});Every resource is available as a property on WeavrClient:
| Property | Covers |
|---|---|
weavr.auth |
Login (password/biometric), identities, access tokens, logout |
weavr.accounts |
Managed Accounts: CRUD, IBAN, block/unblock, statements |
weavr.cards |
Managed Cards: CRUD, physical upgrade, spend rules, statements |
weavr.consumers |
Consumer onboarding, profile updates, email verification, KYC |
weavr.corporates |
Corporate onboarding, profile updates, email verification, KYB, fee charges |
weavr.users |
Authorised users: CRUD, activation, invites, MFA enrolment |
weavr.transfers |
Fund movement between instruments of the same identity |
weavr.sends |
Outgoing wire transfers to other identities/external accounts |
weavr.linkedAccounts |
External bank account linking |
weavr.bulk |
Bulk operation submission and lifecycle (execute/pause/resume/cancel) |
weavr.simulator |
Sandbox-only simulation of transfers, card transactions, KYC/KYB |
weavr.stepUp |
SCA step-up via OTP |
weavr.passwords |
Password set/change/forgot flows |
weavr.backOffice |
Server-to-server Back Office operations (separate auth scheme) |
Each method's JSDoc documents the exact HTTP verb and path it calls — see the source under src/resources/ or your editor's hover tooltips.
import { WeavrClient, isWeavrAPIError, isWeavrValidationError } from "weavr-sdk";
try {
await weavr.accounts.create(token, { profileId: "", friendlyName: "x", currency: "GBP" });
} catch (err) {
if (isWeavrValidationError(err)) {
// caught before any network call — bad input
console.error(`invalid field: ${err.field}`);
} else if (isWeavrAPIError(err)) {
if (err.isStepUpRequired()) {
// trigger the step-up flow and retry with the new token
} else if (err.isRateLimited()) {
// back off further (the SDK already retried automatically)
} else {
console.error(err.statusCode, err.errorCode, err.message, err.syntaxErrors);
}
} else {
throw err; // WeavrNetworkError, WeavrTimeoutError, or something unexpected
}
}| Error | When it's thrown |
|---|---|
WeavrValidationError |
A request fails client-side checks before any network call is made |
WeavrAPIError |
The API responds with a non-2xx status; carries statusCode, errorCode, message, requestId, syntaxErrors, and classification helpers |
WeavrNetworkError |
DNS/TLS/connection failure, or a non-JSON response body |
WeavrTimeoutError |
The request exceeded timeoutMs, or was cancelled via AbortSignal |
Every mutating method accepts an optional trailing idempotencyKey argument, sent as the idempotency-ref header:
await weavr.transfers.create(token, req, crypto.randomUUID());List methods accept an options object with offset/limit plus resource-specific filters:
const { cards, count } = await weavr.cards.list(token, {
offset: 0,
limit: 50,
type: "VIRTUAL",
state: "ACTIVE",
});On Sandbox, use weavr.simulator to exercise flows without waiting on real settlement:
await weavr.simulator.simulateDeposit(token, account.id, {
transactionAmount: { currency: "GBP", amount: 10_000 }, // £100.00, minor units
});
await weavr.simulator.simulateKyc(token, consumerId, { kycState: "APPROVED" });const bulk = await weavr.bulk.submit(token, "users", {
operations: users.map((u) => ({ name: u.name, surname: u.surname, email: u.email })),
});
await weavr.bulk.execute(token, bulk.bulkId);
// poll or listen for webhooks, then:
const { operations } = await weavr.bulk.listOperations(token, bulk.bulkId);The Back Office API uses a distinct base URL and token scheme, wired up automatically:
const { token } = await weavr.backOffice.getAccessToken({
identityId: { type: "CORPORATE", id: corporateId },
});
const account = await weavr.backOffice.getManagedAccount(token, accountId);npm install
npm run typecheck # tsc --noEmit
npm run lint # eslint
npm run test # vitest run
npm run test:coverage # vitest run --coverage
npm run build # tsup → dist/ (ESM + CJS + .d.ts)Tests run against a local, dependency-free mock HTTP server (test/testutil/mockServer.ts) — no network access or live Weavr credentials are required to run the suite.
This package mirrors the resource boundaries, method names, and validation behaviour of weavr-go so that teams working across both languages can reason about the two SDKs consistently. Notable TypeScript-side adaptations:
- Go's
context.Contextcancellation maps to an optionalAbortSignalonTransportConfig/per-request timeout. - Go's typed
*int/*bool"pointer means present" pattern for optional query params maps toundefined-means-omitted inbuildQuery. - Go's
errorinterface + sentinel checks (errors.As) map to TypeScript's error subclasses +isWeavr*Errortype guards.
MIT © Kanishka Naik