Skip to main content

SDKs

Orbit publishes three SDKs today: Node.js and Web (feature-complete, on npm) and Python (core-scope, on PyPI). Six more, Go, .NET, Java, PHP, and Ruby, each wrap the platform’s 8 core resources (messaging, voice, contacts, campaigns, verify, webhooks) in workspace source but are not yet published — see Go: core-scope, not full parity, .NET: core-scope, not full parity, Java: core-scope, not full parity, Python: core-scope, not full parity, PHP: core-scope, not full parity, and Ruby: core-scope, not full parity below. Every SDK shares the same auth model (X-API-Key), retry policy (3 attempts on 429/5xx with exponential backoff), idempotency contract (auto-generated Idempotency-Key on every non-GET), and webhook verification format (t=<unix_ts>,v1=<hex_hmac> HMAC-SHA256, 5-minute replay window).
The npm scope is @devotel-orbit — npm install @devotel-orbit/node and npm install @devotel-orbit/web resolve today. Python is on PyPI: pip install devotel-orbit-sdk (import it as orbit_sdk). Go, .NET, Java, PHP, and Ruby now wrap 8 core resources in workspace source (see below) but none is full parity, and none is published to its package registry yet — build against the REST API directly for those languages, or vendor the SDK source. The REST API recipes cookbook walks the core send/verify/contacts/risk flows task by task, with the Node SDK as the second snippet on each; the API recipes hub is the landing that fans out to the four deep sub-cookbooks (operations, contact lifecycle, US 10DLC pre-send chain, third-party migrators) and the per-language recipes page. Anything the core-scope clients don’t wrap is still reachable: each of the unpublished SDKs ships an escape hatch (client.Request* / client.request) — every per-language page shows a worked example hitting a real uncovered route (Go, .NET, Java, Python, PHP, Ruby).

Map the SDK surface

Before you pick a language, compare what each SDK actually wraps. Every server SDK authenticates with an X-API-Key header and targets https://api.orbit.devotel.io/api/v1 by default; the client SDKs authenticate with a publishable key (dv_live_pk_…) and never carry a secret. Cursor pagination (cursor + has_more) is the convention across every list endpoint — there is no offset-based paging. The table below maps the rest. Each row links to the SDK’s own reference page for the per-language signatures and the full resource list. The Errors column distinguishes the typed SDKs (which throw typed exception classes you can branch on — see the error hierarchy) from the raw REST surface, where every non-2xx response returns an error.code string in the response body. The Realtime column marks which SDKs open a streaming connection for inbound chat and inbox events (SSE on the client SDKs); the server SDKs are request/response only — push delivery to your backend arrives over webhooks, verified with the webhook verifier below.

Quick start: same call in six languages

One authenticated GET /api/v1/me against https://api.orbit.devotel.io/api/v1 — a copy-and-run probe that confirms your key works and shows the { data, meta } envelope every endpoint returns. Node runs it through the typed SDK (orbit.me.get()); Python, Go, Ruby, and PHP run the same call through each client’s request escape hatch, which carries the same auth, retry, and error model as the typed methods.
Each tab fans out to its own page for the full first-send quickstart: cURL and API recipes, Node, Python, Go, Ruby, and PHP. For Go, Ruby, and PHP, the caveat from the Note above stands: none of the three is published to its package registry yet, so vendor the SDK source from the monorepo (or call the REST API directly) before you run the tab.

Start with…

  • Node if you need the full feature surface — it is the only feature-complete SDK today (/sdks/node).
  • Web if you are embedding chat or an inbox widget in a browser (/sdks/web).
  • Python if you want a published, core-scope server SDK on PyPI (/sdks/python).
  • Go / .NET / Java / PHP / Ruby if you are on one of those stacks and the 8 core resources (messaging, voice, contacts, campaigns, verify, webhooks, numbers, lookup) cover your needs — vendor the source until each lands on its registry.
  • Swift / Android / Flutter / React Native if you are building a native client app that shows inbox chat, owned messages, or video rooms — never for backend calls that need a secret key.

Mobile parity

There is no single “mobile” SDK that the Swift, Android, and React Native packages converge on — each is a separate native implementation of the same client-scope surface (inbox chat, owned content cards, video rooms, and on iOS VoIP push for inbound calls). Drift between them is intentional and tracked on each package’s README: parity is owned at the scope contract level (the same end-user surfaces), not at a shared codebase. If one mobile SDK exposes a surface another does not, that is a deliberate scoping decision documented in that SDK’s README, not a gap to backfill — file an issue on the package that is behind if you need the surface promoted into the shared scope.

Published SDKs

Node.js / TypeScript

npm install @devotel-orbit/node — hand-written, fully typed. Node 18+. Status: feature-complete, published on npm.

Web (browser)

npm install @devotel-orbit/web — embeddable chat widget + inbound APIs. Status: feature-complete, published on npm.

Python

pip install devotel-orbit-sdk — messaging, voice, contacts, campaigns, verify. Status: core-scope, published on PyPI.

In workspace source (unpublished)

Go

Messaging, voice, contacts, campaigns, verify. Source-only, NOT published.

Ruby

Messaging, voice, contacts, campaigns, verify. Source-only, NOT published.

PHP

Messaging, voice, contacts, campaigns, verify. Source-only, NOT published.

Java

Messaging, voice, contacts, campaigns, verify. Source-only, NOT published.

.NET / C#

Messaging, voice, contacts, campaigns, verify. Source-only, NOT published.

Go: core-scope, not full parity

Source: packages/sdk-go/ (module github.com/devotel/orbit-go) now wraps 8 core resources with typed methods and its own test suite: messaging (SMS/WhatsApp/email via client.Messages()), voice (client.Voice()), contacts (client.Contacts()), campaigns (client.Campaigns()), verify/OTP (client.Verify()), and webhook signature verification (orbit.VerifyWebhook). This is no longer an empty placeholder. It is not feature-complete against the Node SDK, and it is unpublished / pre-GA like every non-Node/Web language today — do not advertise it to customers as install-ready. Sub-resources the Node SDK exposes are intentionally out of scope for now: voice conferences/IVR/dialer/recordings, contact lists/segments/scoring, and the verify voice-biometrics endpoints. For those, use the Node SDK or call the REST API directly (the Go client also exposes a low-level client.Request(ctx, method, path, ...) escape hatch). See packages/sdk-go/README.md’s Scope section for the authoritative, up-to-date list of what is and isn’t wrapped.

.NET: core-scope, not full parity

Source: packages/sdk-csharp/ (package Orbit.Sdk, targets .NET 8.0) also wraps the same 8 core resources with typed methods and its own test suite: messaging (SMS/WhatsApp/email via client.Messages), voice (client.Voice), contacts (client.Contacts), campaigns (client.Campaigns), verify/OTP (client.Verify), and webhook signature verification (Webhooks.Verify). Like Go, this is no longer an empty placeholder. It is not feature-complete against the Node SDK, and it is unpublished / pre-GA like every non-Node/Web language today — do not advertise it to customers as install-ready. Sub-resources the Node SDK exposes are intentionally out of scope for now: RCS, agents, conversations, billing, and voice recordings/transcripts/conferences/IVR/dialer. For those, use the Node SDK or call the REST API directly (the .NET client also exposes a low-level client.RequestAsync(method, path, ...) escape hatch). See packages/sdk-csharp/README.md’s Scope today section for the authoritative, up-to-date list of what is and isn’t wrapped.

Java: core-scope, not full parity

Source: packages/sdk-java/ (JDK 11+, no live Maven coordinates yet — the registry moves off the retired legacy name before publish) also wraps the same 8 core resources with typed methods and its own test suite: messaging (SMS/WhatsApp/email via client.messages), voice (client.voice), contacts (client.contacts), campaigns (client.campaigns), verify/OTP (client.verify), and webhook signature verification (Webhooks.verify). Like Go and .NET, this is no longer an empty placeholder. It is not feature-complete against the Node SDK, and it is unpublished / pre-GA like every non-Node/Web language today — do not advertise it to customers as install-ready. Sub-resources the Node SDK exposes are intentionally out of scope for now: WhatsApp templates, message streaming, contact segments/lists/opt-outs, campaign journeys/A-B tests, voice recordings/transcripts/conferences/IVR/dialer, verify voice-biometrics, plus RCS, agents, conversations, and billing. For those, use the Node SDK or call the REST API directly (the Java client also exposes a low-level client.request(method, path, ...) escape hatch). See packages/sdk-java/README.md’s Scope section for the authoritative, up-to-date list of what is and isn’t wrapped.

Python: core-scope, not full parity

Source: packages/sdk-python/ (published on PyPI — install with pip install devotel-orbit-sdk; the module imports as orbit_sdk) also wraps the same 8 core resources, fully hand-written against the Python standard library (urllib.request, zero runtime dependencies), with its own pytest suite: messaging (SMS/WhatsApp/ email via client.messages), voice (client.voice), numbers + HLR lookup (client.numbers, client.lookup), contacts (client.contacts), campaigns (client.campaigns), verify/OTP (client.verify), and webhook signature verification (verify_webhook). Like Go, .NET, and Java, this is no longer an empty placeholder. It is not feature-complete against the Node SDK — published on PyPI, but core-scope. Sub-resources the Node SDK exposes are intentionally out of scope for now: RCS, agents, conversations, billing, contact lists/segments/scoring, campaign journeys/A-B tests, and voice recordings/transcripts/conferences/IVR/dialer. For those, use the Node SDK or call the REST API directly (the Python client also exposes a low-level client.request(method, path, ...) escape hatch). See packages/sdk-python/README.md’s Scope section for the authoritative, up-to-date list of what is and isn’t wrapped.

PHP: core-scope, not full parity

Source: packages/sdk-php/ (PHP 8.1+, no Packagist package live yet — the registry moves off the retired legacy name before publish) also wraps the same 8 core resources with typed methods and its own PHPUnit suite: messaging (SMS/WhatsApp/email via $client->messages), voice ($client->voice), contacts ($client->contacts), campaigns ($client->campaigns), verify/OTP ($client->verify), and webhook signature verification (Webhooks::verify). Like Go, .NET, Java, and Python, this is no longer an empty placeholder. It is not feature-complete against the Node SDK, and it is unpublished / pre-GA like every non-Node/Web language today — do not advertise it to customers as install-ready. Sub-resources the Node SDK exposes are intentionally out of scope for now: voice conferences, IVR flows/intents, the outbound dialer, SIP trunks, voice clones, VAQI analytics, live transcript streaming, contact lists/segments, and voice-biometric caller authentication. For those, use the Node SDK or call the REST API directly (the PHP client also exposes a low-level OrbitClient::request(method: ..., path: ..., ...) escape hatch). See packages/sdk-php/README.md’s Scope section for the authoritative, up-to-date list of what is and isn’t wrapped.

Ruby: core-scope, not full parity

Source: packages/sdk-ruby/ (future gem name orbit_sdk, targets Ruby 2.7+) also wraps the same 8 core resources with typed methods and its own RSpec suite: messaging (SMS/WhatsApp/email via client.messages), voice (client.voice), contacts (client.contacts), campaigns (client.campaigns), verify/OTP (client.verify), and webhook signature verification (OrbitSdk::Webhooks.verify). Like Go, .NET, Java, Python, and PHP, this is no longer an empty placeholder. It is not feature-complete against the Node SDK, and it is unpublished / pre-GA like every non-Node/Web language today — do not advertise it to customers as install-ready. Sub-resources the Node SDK exposes are intentionally out of scope for now: RCS, agents, conversations, billing, voice recordings/transcripts/conferences/IVR/dialer, contact lists/segments/scoring, campaign journeys/A-B tests, and verify voice-biometrics. For those, use the Node SDK or call the REST API directly (the Ruby client also exposes a low-level client.request(method, path, **opts) escape hatch). See packages/sdk-ruby/README.md’s Scope section for the authoritative, up-to-date list of what is and isn’t wrapped.

Client / mobile SDKs (different scope, by design)

Besides the two server-capable SDKs above, the workspace also ships client-embed SDKs for native apps — each with its own quickstart page: Swift / iOS (source: packages/sdk-swift/, shipped as Swift Package Manager libraries), Android (Kotlin) (source: packages/sdk-android/, Gradle/Maven), Flutter (source: packages/sdk-flutter/, Dart), and React Native (source: packages/sdk-react-native/, npm). These are not thin ports of the Node SDK and are not meant to grow into one. Each is scoped to the same end-user-facing surfaces the Web SDK’s widget mode covers — conversations/inbox chat, owned in-app messages/content cards, video rooms, and (on Swift) VoIP push registration for inbound-call delivery — and authenticates only with a publishable key (dv_live_pk_…), because they ship inside a distributed app binary. They deliberately do not expose the backend/management resource clients (messaging, whatsapp, email, contacts, campaigns, verify, billing, etc.) — those require a secret key and must only ever be called from a backend, via the Node SDK or the REST API directly. If a client/mobile SDK’s file count looks small next to Node’s, that is this intentional split, not a gap to fill.

Client / mobile SDK sources

For the sensor-exemption contract each client/mobile SDK’s README must honor:
  • Source: packages/sdk-web/ — Web (browser, TypeScript, npm). README documents the deliberate scope as a “Scope — this is a client SDK, not a full API client” heading.
  • Source: packages/sdk-swift/ — iOS (Swift, SPM). README documents the deliberate scope as a “Scope — this is a client SDK, not a full API client” heading.
  • Source: packages/sdk-android/ — Android (Kotlin/Gradle). Same deliberate scope heading in its README.
  • Source: packages/sdk-flutter/ — Flutter (Dart, pub). Same deliberate scope heading in its README.
  • Source: packages/sdk-react-native/ — React Native (TypeScript). Same deliberate scope heading in its README.

Registry coordinates

Node, Web, and Python are published to their package registries today. The remaining languages have no public registry entry yet — the package names below for those describe the future coordinates and may change before first publish. The publishable npm scope is @devotel-orbit (the @devotel npm org is not ours), so the two npm SDKs ship as @devotel-orbit/node and @devotel-orbit/web. Non-npm coordinates are unaffected. Each SDK already has a quickstart page wired into the docs nav — the core-scope Python, Go, Ruby, PHP, Java, and .NET pages, the client/mobile Swift, Android, Flutter, and React Native pages, and the two feature-complete pages /sdks/node and /sdks/web. Each per-language page carries a first-send quickstart, an OTP verify round trip, and one paginated list example against a cursor-based endpoint — the pattern explained prose-side in the Pagination guide — plus a cross-link to the runnable repositories on Starter examples. Once each SDK lands on its registry, its page carries the production install command, a version pin, and the per-language quickstart. The codegen pipeline that drives this lives at tools/sdk-codegen/README.md.

Vendoring Java and C#

Java and .NET ship no public registry package yet, so vendor the monorepo source directly. The flow below is the same shape for both: build the vendored source, authenticate, hit an endpoint the typed clients don’t wrap with the untyped request helper, then send one SMS and poll its delivery status:
Build the SDK jar (mvn package in packages/sdk-java/, JDK 11+, zero runtime dependencies) and put it on your project’s classpath — java -cp target/orbit-sdk-*.jar:. Main runs the class below:
The GET /api/v1/numbers call passes the untyped request helpers (client.request in Java, client.RequestAsync in C#) a route the typed resources don’t wrap — deliberately exercising the escape hatch’s auth, retry, and error model before the first typed call. Both languages share the same pre-publish shape (source-only, Java / C# below), so the vendor step is an explicit prerequisite of the Java and C# quickstart pages, which both assume the package is already on your build path.

Common patterns across languages

Authentication

Every SDK authenticates with an X-API-Key. The GA Node SDK exposes a single constructor — new Orbit({ apiKey }) (alias new Devotel({ apiKey })) — and you pass your own env var (e.g. process.env.ORBIT_API_KEY); the Web surfaces take a publicKey instead. There is no fromApiKey() static or from_env() helper on the GA SDKs today — those are roadmap-language for the codegen’d clients, so the From env column below is marked Roadmap on the still-roadmap languages that list one (core-scope languages that already implement it are marked with their own status instead). The GA Node and Web rows have no fromApiKey/env-reading helper — only the constructor shown in the Direct column.

Webhook verification

Webhook verification is server-side only — the Web SDK does not expose a verifier (browser surfaces never receive inbound webhooks). Each server-side SDK exposes a one-call verifier that returns the decoded event on success or throws OrbitWebhookSignatureError on any failure (malformed header, expired timestamp, signature mismatch, invalid JSON):
  • Node (GA): Orbit.webhooks.constructEvent(body, signature, secret)
  • Python (core-scope, published): verify_webhook(payload=..., signature=..., secret=...)
  • Go (core-scope, unpublished): orbit.VerifyWebhook(body, header, secret, 0, time.Time{})
  • PHP (core-scope, unpublished): Webhooks::verify(payload: ..., signature: ..., secret: ...)
  • Ruby (core-scope, unpublished): OrbitSdk::Webhooks.verify(payload:, signature:, secret:)
  • Java (core-scope, unpublished): Webhooks.verify(body, signature, secret)
  • C# (core-scope, unpublished): Webhooks.Verify(payload, signature, secret)
A complete framework handler per language — raw-body handling, header fallback, 401 on failure — lives at Verify webhook signatures with the SDK; a no-SDK, standard-library variant for Python, Go, Ruby, and PHP is at Verify webhook signatures with no SDK.

Worked example

The same end-to-end flow — connect, send one SMS, verify an inbound webhook — in the exact constructor and method signatures above. Keep it under ten lines per step; per-language detail lives on each SDK’s own page.
The flow above stops at send + webhook. The recipes that round out the core loop — send + DLR webhook consumption, batch send with an idempotent 429 backoff, the full OTP send/check round trip, and a paginated usage/deliverability read — each have a per-language tab (cURL plus all eight server SDKs) on the Per-language recipes guide. For error handling, branch on the subclasses the error hierarchy names. In Node, distinguish a retryable rate limit from an unretryable validation failure:

Error hierarchy

Every SDK exposes the same error tree:
  • OrbitApiError (base) → catch this to handle any non-2xx API response. Carries code, statusCode (aliased as status), details, docsUrl, and requestId, plus isRateLimited / isClientError / isServerError getters.
  • OrbitAuthError — 401/403 (bad API key or missing scope).
  • OrbitNotFoundError — 404 (resource doesn’t exist or isn’t visible).
  • OrbitRateLimitError — 429. Check the Retry-After header (also surfaced in details) to decide when to retry.
  • OrbitValidationError — 400/422 (request body failed server-side validation).
  • OrbitServerError — 5xx after retries exhausted, or persistent network failure.
  • OrbitWebhookSignatureError — webhook verification failed. Carries a code of 'bad_signature' | 'expired' | 'malformed'. Extends Error, not OrbitApiError, so a broad catch (OrbitApiError) block can’t accidentally swallow + retry forgeries.

Operator: publishing checklist

See tools/sdk-codegen/README.md for the per-registry publish commands. The remaining unpublished SDKs (Go, Ruby, PHP, Java, .NET, and the client languages) are committed source-only; first publish to each registry is an operator action.