Skip to main content

Installation

npm install @keystoneos/sdk
The SDK requires Node.js 18+ and has zero runtime dependencies (uses built-in fetch and crypto).

Initialize the client

import { KeystoneClient } from "@keystoneos/sdk";

const client = new KeystoneClient({
  clientId: process.env.KEYSTONE_CLIENT_ID!,
  clientSecret: process.env.KEYSTONE_CLIENT_SECRET!,
});
The client automatically fetches and caches Auth0 M2M tokens. Tokens are refreshed 60 seconds before expiry.

Configuration options

OptionTypeDefaultDescription
clientIdstringrequiredAuth0 M2M client ID
clientSecretstringrequiredAuth0 M2M client secret
environmentstring"production""development", "staging", or "production"
baseUrlstringper environmentOverride API base URL
maxRetriesnumber3Max retry attempts on 429/5xx
retryBaseDelaynumber500Base delay in ms for exponential backoff
timeoutnumber30000Request timeout in ms

Resources

The client exposes typed resource namespaces:
client.settlements    // Create, get, list, compliance decisions, events
client.instructions   // Submit, get, list, cancel bilateral instructions
client.templates      // List and get settlement templates (read-only)
client.webhooks       // CRUD + test, rotate secret, delivery logs
client.environments   // CRUD + deactivate
client.compliance     // Submit compliance decisions (convenience wrapper)

Submit a bilateral instruction

const instruction = await client.instructions.submit({
  templateSlug: "cross_platform_dvp",
  role: "seller",
  party: {
    externalReference: "SELLER-001",
    name: "BNY Mellon Fund A",
    walletAddress: "0x1234567890abcdef1234567890abcdef12345678",
    chainId: 11155111,
  },
  legs: [
    {
      instrumentId: "BOND-2026-A",
      quantity: "1000000",
      direction: "deliver",
    },
  ],
  timeoutAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
  idempotencyKey: client.generateIdempotencyKey(),
});

console.log(instruction.tradeReference); // Use this for the counterparty
console.log(instruction.status);         // "pending_match" or "matched"

List settlements

const { items, total } = await client.settlements.list({
  state: "FINALIZED",
  limit: 20,
  offset: 0,
});

for (const settlement of items) {
  console.log(`${settlement.id} - ${settlement.state}`);
}

Webhook signature verification

import { KeystoneClient } from "@keystoneos/sdk";

// In your webhook handler (Express, Fastify, etc.)
app.post("/webhooks/keystone", (req, res) => {
  const signature = req.headers["x-keystone-signature"] as string;
  const payload = JSON.stringify(req.body);

  const isValid = client.webhooks.verifySignature(
    payload,
    signature,
    process.env.WEBHOOK_SECRET!,
  );

  if (!isValid) {
    return res.status(401).send("Invalid signature");
  }

  // Process the event
  const event = req.body;
  console.log(`Settlement ${event.data.settlement_id} -> ${event.data.to_state}`);

  res.status(200).send("ok");
});

Error handling

The SDK throws typed errors you can catch and handle:
import { ApiError, AuthenticationError, RetryExhaustedError } from "@keystoneos/sdk";

try {
  await client.settlements.get("non-existent-id");
} catch (error) {
  if (error instanceof ApiError) {
    console.log(error.status);  // 404
    console.log(error.message); // "Settlement not found"
  } else if (error instanceof AuthenticationError) {
    // Token issue - check credentials
  } else if (error instanceof RetryExhaustedError) {
    // All retries failed - service may be down
  }
}

Idempotency

Always use idempotency keys when creating settlements or submitting instructions. The SDK provides a helper:
const key = client.generateIdempotencyKey(); // UUIDv4

// Safe to retry - same key returns existing resource
const settlement = await client.settlements.create({
  idempotencyKey: key,
  // ...
});

API Reference

See the full API reference for all available endpoints and parameters.