TypeScript SDK

Install

npm install @ravi-hq/sdk

Create A Client

import { Ravi } from "@ravi-hq/sdk";

const ravi = new Ravi({
  apiKey: process.env.RAVI_API_KEY!,
});

apiKey is required. Use a ravi_id_... identity key for agent runtime work, or a ravi_mgmt_... management key for account-level operations. The key is an auth fence only — the caller chooses the identity, and every per-identity call sends ?identity=<uuid> automatically.

Choose An Identity

The caller chooses the identity, then calls channels and resources on it. Create one, fetch one by uuid, or — with an identity-scoped key — resolve the single fenced identity with ravi.me().

const identity = await ravi.identities.create({
  name: "shopping-agent",
  email_identifier: "shopping", // email local part; omit to auto-generate
  provision_phone: true,        // also give it a phone number
});

// `email` and `phone` are channel objects — the identifiers are `.address` / `.number`.
console.log(identity.email.address, identity.phone?.number);

// With an identity key you don't have the uuid handy:
const me = await ravi.me(); // the single identity the key is fenced to (throws on a mgmt key)

Identity methods:

MethodPurpose
ravi.identities.create(input)Create an identity, optionally with email local part and phone provisioning
ravi.identities.list()List identities visible to the key
ravi.identities.get(uuid)Fetch one identity
ravi.identities.update(uuid, patch)Update identity metadata
ravi.identities.provisionPhone(uuid)Add a phone number to an existing identity

Wait For A Verification Code

The killer use case: send a request, then block until the OTP or verification message lands. waitFor polls the channel’s inbox and resolves with the first matching message.

// Email verification: trigger a signup, then wait for the confirmation email.
await identity.email.send("signup@service.com", "Sign me up", "…");
const msg = await identity.email.waitFor((m) => m.subject.includes("verify"), {
  timeoutMs: 120_000,
});
await msg.reply("got it"); // messages carry behaviour: reply/replyAll/forward/markRead

// SMS OTP: wait for the 6-digit code on the identity's number.
await identity.phone?.send("+15551234567", "START");
const otp = await identity.phone?.waitFor((m) => /\d{6}/.test(m.body), {
  timeoutMs: 120_000,
});
console.log(otp?.body);

Email Channel

identity.email is the identity’s inbox as a channel. Send from it, list the flat inbox or the grouped threads, and act on returned EmailMessage objects.

const msg = await identity.email.send(
  "user@example.com",
  "Hello",
  "Greetings from my AI agent",
);

const inbox = await identity.email.inbox({ unread: true }); // flat EmailMessage list
const threads = await identity.email.threads();             // grouped view

await msg.reply("Thanks!");
await msg.forward("ops@acme.com");
await msg.markRead();

The TypeScript SDK uses the API’s snake_case response fields. It does not remap wire fields to camelCase.

Phone Channel

identity.phone is the identity’s number as a channel (or null if no number is provisioned). Send SMS, list conversations, or place voice calls.

const sms = await identity.phone?.send("+15551234567", "Your code is 482910");

const inbox = await identity.phone?.inbox({ unread: true }); // flat SmsMessage list
const conversations = await identity.phone?.conversations();

// Place an outbound voice call from the identity's number.
const call = await identity.phone?.call("+15551234567");
const transcript = await call?.transcript();

Vault And Contacts

Credentials and the contact directory live under the identity.

await identity.vault.passwords.create({ domain: "acme.com", username: "agent", password: "…" });
await identity.vault.secrets.create({ key: "OPENAI_API_KEY", value: "sk-…" });

const contact = await identity.contacts.find("user@example.com");

Events

Replay durable events after your last processed cursor:

const events = await ravi.events.list({
  since: lastSeq,
  limit: 100,
  event_types: ["call.ended", "email.message.received"],
});

API Keys

Management keys and identity keys are available through ravi.apiKeys.

const managementKey = await ravi.apiKeys.management.create("ci");
console.log(managementKey.key); // full value is returned once

const identityKey = await ravi.apiKeys.identity.create("shopping-agent", identity.uuid);
console.log(identityKey.key); // full value is returned once

Webhook Verification

Ravi signs deliveries with X-Ravi-Timestamp and X-Ravi-Signature.

import { verifyWebhookSignature, WebhookSignatureError } from "@ravi-hq/sdk";

app.post("/webhooks/ravi", async (req, res) => {
  const rawBody = await readRawBody(req);

  try {
    verifyWebhookSignature(
      rawBody,
      req.headers["x-ravi-timestamp"],
      req.headers["x-ravi-signature"],
      process.env.RAVI_WEBHOOK_SECRET!,
    );
  } catch (error) {
    if (error instanceof WebhookSignatureError) {
      return res.status(401).end();
    }
    throw error;
  }

  const event = JSON.parse(rawBody);
  res.status(202).end();
});

Public Exports

The package exports the Ravi client, resource classes, resource input types, API models, typed errors, and webhook verification helpers from @ravi-hq/sdk.

Top-level exports include Ravi, RaviError subclasses, resource classes, API model types, verifyWebhookSignature, and WebhookSignatureError.

Next Steps