Skip to main content

Installation

npm install @getimmutable/sdk
Requirements: Node.js 18+ (uses native fetch)

Setup

import { ImmutableClient } from "@getimmutable/sdk";

const client = new ImmutableClient({
  apiKey: "imk_your_api_key_here",
  baseUrl: "https://getimmutable.dev",
  // timeout: 30000, // optional, in milliseconds
});
OptionTypeRequiredDescription
apiKeystringYesYour imk_ prefixed API key
baseUrlstringYesBase domain (SDK appends /api/v1/...)
timeoutnumberNoRequest timeout in milliseconds

Tracking Events

Direct Tracking

const result = await client.track({
  actor_id: "user_2hG9kLm",
  actor_name: "Sarah Chen",
  actor_type: "user",
  action: "document.created",
  action_category: "documents",
  resource_id: "doc_8nXpQr3",
  resource_name: "Q4 Financial Report",
  resource: "document",
  metadata: { folder: "reports", template: "quarterly" },
  targets: [
    { type: "folder", id: "folder_3mK9pLq", name: "Shared Reports" },
  ],
  session_id: "sess_4kN8pLm",
  tenant_id: "org_7rT2xBc",
  idempotency_key: "unique_key_123",
});

console.log(result.id);     // "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
console.log(result.status); // "queued"

Fluent Builder

The PendingEvent class provides a chainable API:
import { ImmutableClient, PendingEvent } from "@getimmutable/sdk";

const client = new ImmutableClient({
  apiKey: "imk_your_api_key_here",
  baseUrl: "https://getimmutable.dev",
});

const event = new PendingEvent(client, {
  id: "user_2hG9kLm",
  name: "Sarah Chen",
  type: "user",
});

const result = await event
  .idempotencyKey("unique_key_123")
  .version(1)
  .session("sess_4kN8pLm")
  .actionCategory("documents")
  .target("folder", "folder_3mK9pLq", "Shared Reports")
  .target("team", "team_5bR7cNx", "Engineering")
  .track("document.created", "document", {
    folder: "reports",
    template: "quarterly",
  });

PendingEvent Methods

MethodParametersDescription
idempotencyKey(key)stringSet deduplication key
version(v)numberSet event schema version
session(id)stringSet session identifier
actionCategory(cat)stringSet action category
target(type, id?, name?, metadata?)string, string?, string?, object?Add a single target
targets(arr)arraySet all targets at once
track(action, resource?, metadata?)string, string?, object?Send the event

Batch Ingestion

Send up to 100 events in a single request:
const results = await client.trackBatch([
  {
    actor_id: "user_2hG9kLm",
    actor_name: "Sarah Chen",
    action: "document.created",
    resource_id: "doc_8nXpQr3",
    resource_name: "Q4 Financial Report",
  },
  {
    actor_id: "user_2hG9kLm",
    actor_name: "Sarah Chen",
    action: "document.shared",
    resource_id: "doc_8nXpQr3",
    targets: [
      { type: "team", id: "team_5bR7cNx", name: "Engineering" },
    ],
  },
]);

// results.events = [{ id: "...", status: "queued" }, ...]

Querying Events

const response = await client.getEvents({
  actor_id: "user_2hG9kLm",
  action: "document.*",
  from: "2026-03-01T00:00:00Z",
  to: "2026-03-31T23:59:59Z",
  limit: 25,
});

console.log(response.data);              // Event[]
console.log(response.pagination.has_more); // boolean
console.log(response.pagination.total);    // number

// Cursor pagination
if (response.pagination.has_more) {
  const nextPage = await client.getEvents({
    cursor: response.pagination.next_cursor,
  });
}

Retrieving a Single Event

const event = await client.getEvent("9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d");

console.log(event.actor.id);                     // "user_2hG9kLm"
console.log(event.integrity.event_hash);          // "a3f2c8d1..."
console.log(event.integrity.previous_event_hash); // "7b9e1d3f..."

Verification

const result = await client.verify();
console.log(result.data.valid);          // true
console.log(result.data.events_checked); // 4821

// With date range
const ranged = await client.verify(
  "2026-03-01T00:00:00Z",
  "2026-03-31T23:59:59Z"
);

Viewer Tokens

const token = await client.createViewerToken({
  tenantId: "org_7rT2xBc",
  actorId: "user_2hG9kLm",
  ttl: 7200, // 2 hours (min 60, max 86400, default 3600)
});

console.log(token.token);      // "eyJhbGciOiJIUzI1NiIs..."
console.log(token.expires_at); // "2026-03-26T12:15:00Z"

Alerts

const alerts = await client.getAlerts({
  rule_type: "new_country",
  limit: 25,
});

Exports

// Create export
const exp = await client.createExport({
  actor_id: "user_2hG9kLm",
  from: "2026-03-01T00:00:00Z",
});

// Check status
const status = await client.getExport(exp.id);
console.log(status.status); // "pending" | "processing" | "completed" | "failed"

Error Handling

The SDK throws ImmutableError for API failures:
import { ImmutableClient } from "@getimmutable/sdk";

try {
  await client.track({ action: "document.created" }); // missing actor_id
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message); // "The actor_id field is required."
  }
}

TypeScript Support

The SDK is written in TypeScript with strict mode. All request payloads and response types are fully typed.
import type { Event, TrackPayload, PaginatedResponse } from "@getimmutable/sdk";