Node.js SDK
The official TypeScript SDK for SealTrail. Zero dependencies, full type safety, works everywhere.
Installation
npm install sealtrailAlso works with yarn, pnpm, and bun:
yarn add sealtrail
pnpm add sealtrail
bun add sealtrailQuick start
import { SealTrail } from "sealtrail";
const st = new SealTrail({ apiKey: "stl_live_..." });
// Log an event
const event = await st.events.log({
actor: "user_123",
action: "document.signed",
resource: "doc_456",
context: { ip: "203.0.113.42" },
});
console.log(event.id); // "evt_..."
console.log(event.hash); // "sha256:..."
// Verify integrity
const result = await st.events.verify(event.id);
console.log(result.valid); // true
console.log(result.chainIntact); // trueConfiguration
The SealTrail constructor accepts the following options:
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | — | Required. Your API key (stl_live_... or stl_test_...) |
baseUrl | string | https://api.sealtrail.dev | API base URL |
timeout | number | 30000 | Request timeout in milliseconds |
maxRetries | number | 3 | Max retry attempts on 429/5xx/409 errors |
debug | boolean | false | Log requests to console.debug |
fetch | typeof fetch | globalThis.fetch | Custom fetch for edge runtimes |
Resources
Events
All event operations are available on st.events.
Log an event
const event = await st.events.log({
actor: "user_123",
action: "invoice.approved",
resource: "inv_456",
context: { ip: "192.168.1.1", amount: 1500 },
chain: "billing", // optional — defaults to "default"
});List events with filters
const { data, nextCursor } = await st.events.list({
actor: "user_123",
action: "invoice.approved",
after: "2026-03-01T00:00:00Z",
limit: 50,
});
// Manual pagination
if (nextCursor) {
const page2 = await st.events.list({ cursor: nextCursor });
}Auto-pagination
Use listAutoPaginate() to iterate over all events without managing cursors.
It returns an AsyncIterable that fetches pages on demand.
for await (const event of st.events.listAutoPaginate({ actor: "user_123" })) {
console.log(event.action, event.timestamp);
}
Auto-pagination respects the
limit parameter as page size but iterates through
all matching events. It's ideal for exports and batch processing.
Get a single event
const event = await st.events.get("evt_abc123");Verify event integrity
const result = await st.events.verify("evt_abc123");
if (result.valid) {
console.log("Event integrity confirmed");
} else {
console.error("Tamper detected:", result.errors);
}Chains
Hash chain operations are available on st.chains.
List chains
const chains = await st.chains.list();
for (const chain of chains) {
console.log(`${chain.name}: ${chain.eventCount} events`);
}Get chain status
const chain = await st.chains.status("chn_abc123");
console.log(chain.lastHash);
console.log(chain.lastPosition);Error handling
The SDK throws typed errors that map to HTTP status codes. All errors extend SealTrailError.
import {
SealTrail,
SealTrailError,
ValidationError,
RateLimitError,
QuotaExceededError,
NotFoundError,
} from "sealtrail";
try {
await st.events.log({ actor: "", action: "" });
} catch (err) {
if (err instanceof ValidationError) {
console.error("Invalid input:", err.message);
console.error("Details:", err.details); // field-level errors
} else if (err instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${err.retryAfter}s`);
} else if (err instanceof QuotaExceededError) {
console.error("Monthly quota exceeded — upgrade your plan");
} else if (err instanceof NotFoundError) {
console.error("Resource not found");
} else if (err instanceof SealTrailError) {
console.error(`API error [${err.code}]: ${err.message}`);
}
}
The SDK automatically retries on 429 (rate limit), 409 (conflict),
and 5xx errors with exponential backoff.
QuotaExceededError (429) is
not retried since it requires a plan upgrade.
Error classes
| Class | HTTP | When |
|---|---|---|
ValidationError | 400 | Invalid request body or query params |
AuthenticationError | 401 | Missing or invalid API key |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Resource does not exist |
ConflictError | 409 | Chain write conflict (auto-retried) |
RateLimitError | 429 | Too many requests (auto-retried) |
QuotaExceededError | 429 | Monthly event quota exceeded (not retried) |
InternalError | 500 | Server error (auto-retried) |
Supported runtimes
The SDK works in any JavaScript runtime with fetch support:
- Node.js 18+ (native fetch)
- Bun
- Deno
- Cloudflare Workers / Vercel Edge / other edge runtimes
For runtimes without native
fetch, pass a custom implementation via the
fetch config option (e.g. node-fetch or undici).
TypeScript
The SDK ships with full TypeScript declarations. All request params and response types are exported:
import type {
SealTrailConfig,
LogEventParams,
ListEventsParams,
AuditEvent,
VerifyResult,
Chain,
EventListResponse,
} from "sealtrail";