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:
| Method | Purpose |
|---|---|
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.