recalled.dev
Reference

npm SDK

bash
npm install @recalled/sdk

Client

ts
import { Recalled } from "@recalled/sdk";

const client = new Recalled({
  apiKey: process.env.RECALLED_API_KEY!,
  // baseUrl defaults to https://api.recalled.dev/v1
});

Events

ts
// create (strict, throws on failure)
await client.events.create({
  action: "user.password.changed",
  actor: { id: "user_1" },
});

// list
const { data, nextCursor } = await client.events.list({
  limit: 50,
  organization: "org_abc",
});

// search
const { data } = await client.events.search({ q: "invoice" });

// get one
const event = await client.events.retrieve("evt_xxx");

Resilient emit() (recommended)

emit() returns immediately and delivers the event in the background. If the API is unreachable, the SDK holds the event in an in-memory queue and retries automatically with exponential backoff for up to 24 hours. Your request path never sees an exception on a transient outage, which is what you want for audit logs 99% of the time.

ts
client.events.emit({
  action: "invoice.paid",
  actor: { id: user.id, email: user.email },
  organization: user.organizationId,
  metadata: { amount, currency },
});
// returns immediately, no await needed

Delivery outcomes are observed via callbacks on the Recalled constructor:

ts
const client = new Recalled({
  apiKey: process.env.RECALLED_API_KEY!,
  resilience: {
    onDelivered: (input, event) => {},
    onError:     (err, input) => {},
    onDrop:      (input, reason, err) => {
      // reason: "ttl_expired" | "fatal_error" | "queue_full"
    },
  },
});

Flush before exit

Short-lived processes (CLI, cron, Lambda) must await client.flush() before exiting, otherwise pending events are lost when the process terminates.

ts
client.events.emit({ action: "job.completed" });
await client.flush(); // waits up to 30s for the queue to drain

Resilience options

OptionDefaultDescription
maxQueueSize5000Events held in memory
maxAgeMs24hTTL before an event is dropped
minBackoffMs1000First retry delay
maxBackoffMs10minBackoff cap

Pass resilience: false to disable buffering entirely (emit() becomes a raw fire-and-forget).

create vs emit

`create()``emit()`
ReturnPromise<Event>void
Throws on failureyesno
Buffers on outagenoyes
Blocks the request pathyesno
Use whenfailure must surfacefailure must be invisible

Embed

ts
const { token } = await client.embed.createToken({
  organization: "org_abc",
  ttlSeconds: 900,
});

Actors (GDPR)

ts
await client.actors.delete({ id: "user_123" });

Exports

ts
// Returns the raw export body as a string (CSV or JSON per your format).
const body = await client.exports.fetch({
  format: "csv",
  organization: "org_abc",
});

Types

Every method is fully typed and the package ships its own .d.ts. Import types directly when you need them:

ts
import type { Event, CreateEventInput } from "@recalled/sdk";