SDK · @compense/sdk
JavaScript / TypeScript
@compense/sdk 1.1.0: installation, client, configuration, runtimes (Node, Deno, Bun, edge), errors, async pagination, webhook verification with node:crypto or Web Crypto, CLI and testing.
On this page
| Package | @compense/sdk (ESM and CommonJS, with TypeScript declarations) |
| Version | 1.1.0 · API v1 |
| Requirements | Node.js 18+ (uses native fetch); also Deno, Bun, Cloudflare Workers and Vercel/Next.js edge |
| Dependencies | None at runtime |
| Repository | Appiasoft/compense-saas-sdk-js · guides in docs/ · examples in examples/ |
Install #
npm install @compense/sdkimport { CompenseClient } from "@compense/sdk"; // ESM / TypeScript
// const { CompenseClient } = require("@compense/sdk"); // CommonJS
Client #
const client = new CompenseClient({
apiKey: process.env.COMPENSE_API_KEY!, // required; sent as X-API-Key
environment: "sandbox", // "production" (default) | "sandbox" | "dev"
baseUrl: undefined, // another URL; takes precedence over environment
timeout: 30_000, // ms per attempt
retry: { maxAttempts: 3, backoffBaseMs: 500, backoffMaxMs: 30_000, jitter: true, retryWrites: false },
fetch: undefined, // your own fetch (proxy, instrumentation, tests)
logger: console, // deprecation warnings
});There’s a single client and everything returns a Promise. The key is a server secret: even though
the client works in browsers, never put a key in frontend code.
Conventions #
camelCasemethods and an options object for parameters:client.wallet.bills.pay({ document, billerCode, reference, amount, idempotencyKey }).- Free-form fields (
extra, andfieldsin the administrative module) are sent as is, with the contract’ssnake_casenames. - Durations in milliseconds (
timeout,backoffBaseMs), excepterr.retryAfter, which is in seconds like the header. - Path parameters are percent-encoded.
Errors #
import {
CompenseError, CompenseConfigError, CompenseAPIError, AuthError, NotFoundError,
IdempotencyConflictError, ValidationError, RateLimitError, UpstreamError, ServerError,
CompenseConnectionError, CompenseTimeoutError,
} from "@compense/sdk";Unlike Python, transport failures are typed: CompenseConnectionError (and its subclass
CompenseTimeoutError). They aren’t retried automatically: resend with the same idempotencyKey.
Async pagination #
Page and OffsetPage walk through all following pages with for await, repeating the same call
with the same filters:
for await (const delivery of await client.webhooks.deliveries.list({ status: "failed" })) {
await client.webhooks.deliveries.replay(String(delivery.id));
}
const first = await client.wallet.transactions.list("1032456789", { limit: 100 });
for await (const page of first.iterPages()) console.log(page.offset, page.length);
const next = await first.getNextPage(); // or null
Webhooks #
| Import | Runtime | API |
|---|---|---|
@compense/sdk/webhooks | Node.js (also Bun, Deno and Workers with Node compatibility) | synchronous verifyWebhook(...) |
@compense/sdk/webhooks/web | Web Crypto: browsers, Cloudflare Workers, Vercel/Next.js edge, Deno | await verifyWebhook(...) |
import { verifyWebhook, WebhookVerificationError } from "@compense/sdk/webhooks";
const event = verifyWebhook(rawBody, req.headers, [NEW_SECRET, OLD_SECRET], { tolerance: 300 });
event.eventId; event.event; event.resource; event.isTest;It takes the raw body (express.raw(), never express.json()). Complete receivers are in
Verifying the signature.
CLI #
The package includes the compense command (Node): npx compense health, events, endpoints,
endpoint-create, trigger, deliveries, replay, clock, simulate, listen and --version.
See CLI.
Testing #
Pass your own fetch:
import { CompenseClient } from "@compense/sdk";
const fakeFetch: typeof fetch = async (input) => {
const url = new URL(String(input instanceof Request ? input.url : input));
if (url.pathname === "/v1/gateway/wallet/balance/") {
return new Response(JSON.stringify({ total: "150000.00", available_cash: "150000.00", currency: "COP" }),
{ status: 200, headers: { "content-type": "application/json" } });
}
return new Response(JSON.stringify({ title: "Not Found", status: 404, trace_id: "t" }), { status: 404 });
};
const client = new CompenseClient({ apiKey: "cmp_test", environment: "sandbox", fetch: fakeFetch });
console.assert((await client.wallet.balance("1032456789")).available.amount === "150000.00");Differences from the Python SDK #
Same operations, bodies, idempotency and retries (the test suite compares each call with what Python sends), with these deliberate differences: a single async client; durations in ms; options objects instead of named arguments; none of the deprecated 1.0 aliases; typed transport errors; async pagination; two webhook verification entry points.