## Install ```bash npm install @ravi-hq/sdk ``` ## Create A Client ```typescript 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=` 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()`. ```typescript 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. ```typescript // 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. ```typescript 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. ```typescript 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. ```typescript 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: ```typescript 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`. ```typescript 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`. ```typescript 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 - [SDK Overview](/sdk/overview/) - [Python SDK](/sdk/python/) - [API Reference](/api/reference/)