Node.js SDK
The official Devotel Node.js SDK provides a fully typed client for the Devotel API. Built with TypeScript, it supports all Devotel services — messaging, voice, agents, flows, numbers, and verify.Installation
Quickstart: send your first SMS
A runnable end-to-end in five lines — the key comes from your environment, never from source. Copy it into a file and run it withnode first-send.mjs:
ORBIT_API_KEY to a sandbox key prefixed dv_test_sk_ first — sandbox
sends are simulated, free, and never reach a carrier. Swap in your live key
(dv_live_sk_...) when you’re ready to send for real; the code does not
change.
The per-channel helpers (sendWhatsApp, sendEmail, …) are covered under
Messaging below, and the full request/response contract —
including language tabs with this exact call — lives on the
Messages API reference. For a complete
runnable project, the two SMS starter repos on
Starter examples build on this exact flow.
Messaging
Voice
The Voice resource exposes call control, recordings, transcripts, conferences, IVR, dialer campaigns, SIP trunks, and analytics. See Voice operations below for the full surface.AI-agent / IVR routing and webhooks are not per-call options. Configure them once on the Application / IVR Flow that owns the number — the call then follows that routing. See Voice operations below.
Voice operations
A complete tour of the live call-control surface. Every snippet matches the actual SDK API inpackages/sdk-node/src/resources/voice.ts.
Make a call
The AI voice agent is bindable per call viaagent_id. When set, the call is dispatched to that named, tenant-scoped voice agent — the server validates it exists and is not archived (the same first-class field shown in the Quickstart).voice.calls.create()acceptsto,from,record,amd,campaignId,orgTimezone,agent_id, andmetadata; any other field is silently stripped by the server. IVR flows and webhooks remain Application / IVR-Flow level configuration, not percreate()overrides. Attach the destination number to an Application (or IVR Flow) and the call inherits its IVR routing and webhook configuration.
Get call details
Hang up a call
Transfer a call
Both cold (blind) and warm (consult-first) transfers are supported on the sametransfer() method:
warmTransfer() forwards its params to the server verbatim, so the field
names below are camelCase exactly as shown — the route validates them
under those keys:
destination— E.164 number to consult-then-bridge to (required).from— optional caller ID presented on the consultation leg.contextWhisper— whentrue, a short summary is spoken to the receiving agent on answer, before the bridge. Defaults tofalse.context— optional custom whisper text (max 220 characters). When omitted whilecontextWhisperistrue, a generic summary is spoken.
Conference call
Conference participant controls
Once a conference is live, the moderator can mute, hold, kick, lock, and record fromorbit.voice.conferences.*. The participantId is the
Jambonz call_sid of the leg (the leg_call_sid field on each row of the
conference detail / listParticipants response):
IVR flows
Trigger a published IVR flow as an outbound session, or browse the flow catalog:Conversational IVR intents
Per-tenant NLU buckets the LLM classifier uses to route free-speech caller utterances to an ACD queue or a direct agent:Outbound dialer campaigns
Manage power/predictive dialer campaigns. Status changes flow through the server’s campaign state machine —start() and pause() are ergonomic
wrappers over the status transition:
SIP trunks
Voice clones & VAQI analytics
Record a call
Recording is started by passingrecord: true at call creation; pause/resume happens via call-control endpoints. After the call ends, fetch the recording metadata and a signed download URL:
Listen to a recording
Live transcript stream (Node-only)
Voice webhook handling
Verify the signature with the shared SDK helper, then dispatch onevent.type:
The signing secret is the dashboard-issued whsec_... value from your endpoint’s
settings (see Webhook Security) — a customer-side secret you
store in your own environment, not an Orbit env.ts variable. Name the env var
whatever you like; ORBIT_WEBHOOK_SECRET is used here.
Verify
The fastest first integration on the platform: send a one-time passcode, then check the code your user types in. Three lines:result.data.valid is false; it never throws for a bad guess (only for
transport/auth failures). The full contract is on the
Verify API reference, and the
OTP sign-in starter repo shows the same flow as
a complete, runnable Next.js app.
Paginate a list
List endpoints are cursor-paginated — each response carriesmeta.pagination.cursor and meta.pagination.has_more, and you pass the
cursor back until has_more is false. Page through SMS messages:
Webhooks
Error Handling
Every non-2xx response is thrown as anOrbitApiError, but the SDK constructs a
status-specific subclass so you can branch on the failure mode. Narrow on the
subclass first, then fall back to the OrbitApiError base. All of these names are
importable from @devotel-orbit/node:
OrbitApiError (base), OrbitAuthError (401/403), OrbitNotFoundError (404),
OrbitRateLimitError (429), OrbitValidationError (400/422), OrbitServerError
(5xx), and OrbitWebhookSignatureError (webhook verification — extends Error,
not OrbitApiError).
Runnable examples
The package’sexamples/ directory holds self-contained, runnable end-to-end
files (each takes ORBIT_API_KEY / ORBIT_WEBHOOK_SECRET from the
environment): cursor pagination over orbit.messages.iter(...), the OTP
send+check round trip, a programmable outbound call with an answer_url
callback, webhook signature verification against a signed test payload, a bulk
contacts CSV import, and a phone-number identity-risk score. Run any of them
with node examples/<name>.js. The API recipes cookbook
walks the same flows task by task.
Configuration
Requirements
- Node.js 18 or later
- TypeScript 5.0+ (recommended but not required)