Requirements
Any runtime with a global fetch: Node 18+, modern browsers, Deno, Bun, or Cloudflare Workers. The SDK has zero runtime dependencies. On Node < 18 you can pass your own fetch implementation (see Configuring the client).
Install
npm install @provableio/sdk
# or: pnpm add @provableio/sdk / yarn add @provableio/sdkThe package ships types generated directly from the OpenAPI spec, so request params and response bodies always stay in sync with the live API.
Configuring the client
Create one ProvableClient and reuse it. All options are optional — an empty client makes anonymous, rate-limited calls.
import { ProvableClient } from "@provableio/sdk";
const client = new ProvableClient({
// API key — sent as the x-api-key header. Use a pk_test_* key for test mode.
apiKey: process.env.PROVABLE_KEY,
// Alternative to apiKey: sent as "Authorization: Bearer <token>".
// bearerToken: process.env.PROVABLE_KEY,
// Defaults to https://api.provable.io. There is no separate sandbox host —
// test mode is selected with a pk_test_* key on the same base URL.
// baseUrl: "https://api.provable.io",
// Headers merged into every request.
// defaultHeaders: { "X-App": "my-service" },
// Custom fetch (required on Node < 18, optional elsewhere).
// fetch: myFetch,
});Test keys vs. live keys
Pass a pk_test_* key to run in test mode: outcomes don't touch live seed state, don't count toward your quota, and don't fire webhooks. Swap in a pk_live_* key for production — no code changes, same base URL. See Test mode vs. live mode.
Handling the result
Every method returns a discriminated ApiResult<T> — either { data, error: null, response } on success or { data: null, error, response } on a non-2xx response. No exceptions are thrown for API errors; only network and abort errors throw, so handle those with try/catch.
const { data, error } = await client.getInts({
clientSeed: "order-42",
count: 5,
min: 1,
max: 100,
});
if (error) {
// error is the typed Error schema from the API.
console.error(`API ${error.code ?? ""}: ${error.error}`);
} else {
console.log(data.outcome); // the integers
console.log(data.serverHash); // commit you can later verify
}The third field, response, is the raw Response if you need headers or the status code. Other RNG helpers follow the same shape: getFloats, shuffle, pick, getBytes, rollDice, and gaussian.
Idempotency-Key retries
Pass an idempotencyKey in the per-request options on any RNG method. A retry within 24 hours returns the original outcome byte-for-byte and doesn't count again toward your daily quota — safe for network retries and at-least-once job queues.
const key = crypto.randomUUID();
const { data, error } = await client.getFloats(
{ clientSeed: "order-42", count: 1 },
{ idempotencyKey: key },
);
// Replaying with the same key returns the same draw, for free:
await client.getFloats({ clientSeed: "order-42", count: 1 }, { idempotencyKey: key });More detail in Idempotency keys.
Streaming with custom headers
streamOutcomes is an async iterator over Server-Sent Events. Unlike the browser EventSource — which can't send custom headers — it forwards your auth header, resumes from a known event via lastEventId, and stops cleanly when you pass an AbortSignal.
const controller = new AbortController();
setTimeout(() => controller.abort(), 30_000); // stop after 30s
for await (const event of client.streamOutcomes(
{ clientSeed: "live-feed" },
{ lastEventId: lastSeenId, signal: controller.signal },
)) {
console.log(event);
lastSeenId = event.id; // persist so you can resume after a disconnect
}See Streaming outcomes for the resume semantics.
Commit / reveal flow
Publish a commitment up front, let participants lock in, then reveal the outcome so anyone can check you didn't change it after the fact.
// 1. Commit before anyone can influence the draw.
const { data: commit, error: commitErr } = await client.createCommit({
clientSeed: "round-1",
});
if (commitErr) throw new Error(commitErr.error);
// Publish commit.commitId / commit.serverHash to participants now.
// 2. Later, after bets are locked, reveal it.
const { data: reveal, error: revealErr } = await client.revealCommit({
commitId: commit.commitId,
});
if (revealErr) throw new Error(revealErr.error);
console.log(reveal.outcome); // the revealed draw
console.log(reveal.serverSeed); // proves the commitmentWalkthrough: Commit-reveal for scheduled draws.
Batch draws
Send several independent draws in one round trip with batch:
const { data, error } = await client.batch({
draws: [
{ kind: "ints", clientSeed: "s1", count: 3, min: 1, max: 6 },
{ kind: "floats", clientSeed: "s2", count: 2 },
],
});Verifying an outcome
const { data, error } = await client.verifyServerHash({
serverSeed: "...",
clientSeed: "order-42",
nonce: 0,
});Verification calls are free. The SDK also wraps the transparency endpoints — listMerkleRoots, getMerkleRoot, and getMerkleProof — for auditing the transparency log.
Escape hatch & raw types
Need an endpoint newer than your installed SDK version? Use the typed low-level request helper, which still applies your auth, base URL, and default headers:
const res = await client.request<MyResponseType>("GET", "/api/some-new-endpoint", {
query: { foo: 1 },
headers: { "X-Custom": "1" },
});You can also import the raw generated OpenAPI types:
import type { paths, components } from "@provableio/sdk";