Skip to main content
Back to blog

Migrating from Vonage Video to Devotel Orbit: session, archive, and SIP cutover runbook

A code-level runbook for the Vonage Video API (TokBox/OpenTok heritage). Map sessions and the session/token pair to Orbit rooms and join tokens, re-host existing archives without re-encoding, move the Vonage SIP interconnect trunks to Orbit SIP, and cut over with a smoke window and a deliberate decommission.

Orbit Editorial Team

Quick answer: Vonage Video (the Video API, built on TokBox's OpenTok stack) is one of the few vendor-of-record video products with a true RTC surface, so its migration runbook has to do something most vendor-swap posts do not: port real-time media sessions, not just callbacks and numbers. The move to Devotel Orbit is bounded. Export your session and archive inventory through the Vonage REST surface, map the session/token/auth triplet to Orbit's server-minted room join flow, re-host existing archives into your own storage without re-encoding, point the Vonage SIP interconnect trunks at Orbit SIP, run a smoke window, then decommission. The capability matrix on Orbit vs Vonage Video credits the room itself parity, so this post spends its pages on the runbook the capability post only gestures at. The Orbit vs Vonage Video head-to-head frames the account-shape question (one bill vs separate product lines); this runbook is the code-level sibling.

If you run Vonage Video in production, the concrete questions this post answers are: which of my TokBox-era session and token concepts move where on Orbit, what happens to my stored archives, and how do I cut over without dropping a live call?

1. Export the Vonage Video estate: sessions, archives, tokens, SIP trunks

The first gate is an inventory, and Vonage Video has four families worth pulling before you touch anything:

  • Sessions. Each Vonage Video session_id is the room equivalent (the TokBox heritage shows in the naming; OpenTok shipped the same object model). Pull every active and recently-closed session via the Session Monitoring REST surface: session id, creation time, connection count, stream minutes, and the archive status. This is the table your Orbit room creation will mirror.
  • Archives. List every archive (GET /v2/project/<apiKey>/archive) per project. For each row, record the archive id, session id, duration, resolution, the status (available, paused, stopped), and the download URL. Archives sitting on Vonage storage are the part of this runbook that does not transfer by themselves; the re-hosting step below handles them.
  • Auth credentials. Vonage Video uses a project-scoped API key plus the session/token pair (OpenTok-style). Token generation is local JWT signing on your backend with the project secret; sessions are either routed or media-server-routed (OpenTok's relay vs routed distinction). Capture which projects route video through which sessions and how many distinct token-vending call sites your codebase has.
  • SIP trunks and dial-in. If you use Vonage's SIP interconnect (the endpoint family that lets a SIP trunk land into or out of a Vonage Video session), list every trunk configured to bridge voice into the video session: the Vonage SIP interface endpoints, the trunk addresses, and the dial-in numbers. This is the only product surface Vonage runs where SIP enters the RTC session directly, and it is the section most "migrate from Twilio" posts skip because Twilio Video did not ship it.

Gate exit: one spreadsheet or inventory file per project with all four families named, and the count of token-vending call sites you will port.

2. Map the RTC surface: sessions, connections, streams, and the token pair

Vonage Video's object model has five levels: Project (the API key scope), Session (the room), Connection (a participant), Stream (a published audio/video stream), and the Token that lets a connection join a session. Orbit's RTC surface covers the same model but consolidates it behind a server-minted join token and a prebuilt element, so the client code shrinks:

Vonage Video conceptDevotel Orbit equivalent
OT.createSession() / POST /v2/project/<apiKey>/sessionCreate the room server-side once: POST /api/v1/video/rooms-scheduled (persistent, named) or POST /api/v1/video/rooms (ad-hoc); the room persists beyond any single session
OT.generateToken({ session_id, role })A participant is an identity plus a grant tier bound into a join token; participant_tier of host, panelist, viewer, or hidden_supervisor
Publisher role (publisher, subscriber, moderator)The effective grant in the join response: permissions.can_publish / permissions.can_subscribe decide publish and subscribe per participant
session.publish(publisher)Publish is implicit at connect: a grant with can_publish: true publishes camera/microphone when the user toggles them; a viewer grant is receive-only
session.on('connectionCreated') / stream eventsDOM events from the embed: orbit-participant-joined, orbit-participant-left, orbit-state, orbit-error, and server-side video.participant.joined / video.participant.left webhooks
session.disconnect()Drop the element or close the LiveKit client; an empty ad-hoc room is reaped promptly, and a scheduled room returns to its scheduled state
Routed session vs relay sessionNot exposed on Orbit: the SFU (LiveKit) routes or relays based on the grant and topology; the operational distinction collapses into the tier you mint
Vonage Video's per-stream audio-fallback / audio-onlyThe QoS telemetry arrives as the video.participant.qos webhook; a participant's publish quality and fallback live server-side in the telemetry, not in client configuration

The most useful frame for the port: on Vonage you ship a client SDK that signs tokens locally against a project secret; on Orbit you mint a self-describing join token server-side and hand it to either the prebuilt orbit-video-room element or a LiveKit client SDK for a custom UI. A Vonage integration that built its own tile/grid UI ports to the LiveKit path; an integration that used Vonage's default embed-style flow ports to the Orbit element and deletes the UI code.

<!-- Vonage: your OpenTok embed + session/token JS -->
<!-- Orbit: the prebuilt room element -->
<script type="module"
  src="https://cdn.jsdelivr.net/npm/@devotel-orbit/web@latest/dist/index.mjs">
</script>

<div style="height:600px">
  <orbit-video-room
    token="SERVER_MINTED_JOIN_TOKEN"
    server-url="ws-url-from-join-response"
    display-name="Support agent"
    enable-screen-share="true"
  ></orbit-video-room>
</div>

3. Token-generation parity: TTL, role constraints, per-participant grants

Vonage's token flow builds a JWT locally with the project secret, with an optional expireTime, role, and per-connection data payload. Orbit's parity surface is the join endpoint; the browser never sees your API key, and every knob Vonage encoded into token construction moves into the join request body:

import { Orbit } from "@devotel-orbit/node";

const orbit = new Orbit({ apiKey: process.env.ORBIT_API_KEY });

// Vonage: OT.generateToken({ sessionId, role: 'publisher',
//   expireTime: Date.now() + 86400 })
// Orbit: POST /api/v1/video/rooms-scheduled/:id/join via the escape hatch.
const join = await orbit.request(
  "POST",
  "/video/rooms-scheduled/room_01HZYJ6W2K/join",
  {
    participant_name: "guest",
    ttl_seconds: 3600, // parity knob for Vonage's token expiry, in seconds
  },
);

console.log(join.data.token);             // livekit-access JWT for the client
console.log(join.data.participant_tier);  // "panelist": the grant tier bound at mint
console.log(join.data.permissions);       // effective grant: read this, never assume
console.log(join.data.expires_in_seconds);

The parity table, knob by knob:

  • TTL. Vonage's expireTime (a unix timestamp on the token) moves to ttl_seconds on the join body (default one hour). Re-issuing is a fresh POST every time; mint a new token when expires_at approaches instead of holding a long-lived JWT.
  • Session access. Vonage's session_id in the token payload moves to the endpoint path itself; the token is minted against a room id, so "which room" is enforced by the resource you called, not by a claim inside the JWT.
  • Role constraints. Vonage's role (subscriber, publisher, moderator) moves to Orbit's grant tiers: host, panelist, viewer, hidden_supervisor. The effective grant is echoed back in permissions (can_publish, can_subscribe, can_publish_data, hidden, room_admin). Port your permission matrix by reading the response, not by assuming the requested tier was granted.
  • Identity binding. Vonage tokens carry an optional data payload for identity loosely enforced by your backend. On Orbit, identity binds at mint time, and minting a token under another user's identity requires the owner or admin role plus a non-empty reason; the spoofing hole an ordinary project secret had on Vonage is closed by design.
  • Routed vs relay. Vonage's session type (routed through media server or p2p relay) rarely changes your integration logic, and on Orbit the SFU picks topology internally. If you gated any session-type decision in client code, delete the gate.

One behavioral difference to plan for: because join tokens are per-participant and short-lived, the token-vending endpoint in your backend stays, but it becomes a thin proxy to the join API instead of a local JWT signer. If your current exchange derives permissions from user records, keep that logic; only the signing step moves.

4. Re-host existing archives: no re-encoding, move the files

Vonage Video archives are stored on Vonage storage with a signed URL per archive; when you stop the subscription the storage goes away. The goal is to preserve the recordings in your own object storage without re-encoding, and to register the new location in whatever database tracks session-to-recording lookup.

  1. Pull the archive list. GET /v2/project/<apiKey>/archive?sessionId=<id> returns per-session archive rows; page the full list per project.
  2. Fetch each archive's download URL. Each available archive row carries a temporary signed URL on Vonage storage (or your configured S3/Azure storage on the partner-storage plans). Download the container (MP4 for composed archives, or a tar of per-stream tracks for individual-stream archiving).
  3. Upload to your own storage. Ship the file untouched (no re-encode, no transcode) to the bucket of your choosing. Keep the Vonage archive_id and session_id as the object key or as metadata so the lookup layer survives.
  4. Update your session-record lookup. Where your app resolves "which recording belongs to this session," repoint the resolver to the new object key.
  5. Decommission Vonage storage after the window lapses. Once the smoke window (below) closes and the download URLs have been replaced on every resolver path, delete the archives on Vonage and clear the project-level storage configuration.

Two parity differences worth writing down in the shim README:

  • Recording consent is per-participant on Orbit. Vonage archives record the whole session or nothing. On Orbit, a participant can decline at join time (allow_recording in the join body), and a host can change consent mid-room; a decliner's media is excluded from the composite and per-track recordings. If your compliance program promised "recording on or off for the room," say so in the join flow rather than discovering per-participant exclusion after go-live.
  • Recording links on Orbit are short-lived by design. Orbit returns a one-hour signed URL on the room record (recording_url with recording_url_expires_at); fetch the room again when the link lapses, or export finished recordings to your own storage and treat Orbit's link as a transfer window, not an archive forever.

5. Move SIP trunks and dial-in: the Vonage SIP interconnect to Orbit SIP

Vonage Video ships a SIP interconnect family: an outbound dial and an inbound dial path that bridges SIP trunks directly into or out of a video session. This is the surface that most vendor-of-record video products do not have, and it is the piece of the port most runbooks miss.

  • Outbound dial from a session. On Vonage, the OT.dial REST endpoint (or the OpenTok Session.dial client) dials a SIP URI from within a session. On Orbit, the SIP dial-out lives on the Orbit SIP trunking surface; re-point the client at Orbit's SIP trunk endpoints and use the same SIP URI shape. The trunk you configure on Orbit carries the dial-out for the session.
  • Inbound dial into a session. Vonage's inbound dial lets a PSTN or SIP caller land into the video session as an audio participant. On Orbit, the inbound bridge is the same SIP trunk you use for the rest of the voice surface; route the dial-in number (or SIP URI) at the trunk, and let the grant tier decide whether the caller publishes or subscribes.
  • The endpoint family, mapped. The Vonage SIP interface endpoints (sip.tokbox.com, sip.vonage.com, and region-scoped variants) map onto Orbit SIP trunk endpoints per region; the UDP/TLS, TCP, and SRTP knobs on the Vonage trunk configuration have parallels on the Orbit SIP trunk surface. Keep the SIP URI naming your existing dialer uses and only change the host portion of the URI.

If you do not use the SIP interconnect family, this section is the smoke for "nothing to port here"; if you do, this is the longest-lived piece of the cutover and the one you should run as a parallel trunk during the smoke window.

One route-map rule keeps the cutover tenant-owned: the SIP trunk surface this section moves is inbound and bridge traffic. Your outbound voice and SMS stay on whichever provider your account already routes through on Orbit; do not wire an inbound/bridge SIP trunk as a new outbound carrier during the port.

6. The staged cutover checklist: smoke window, telemetry parity, decommission

A video migration fails in the phase between "works in staging" and "old vendor turned off." Run it as five gates, each with a rollback state you can name:

  1. Freeze the inventory. List every flow that builds a session or dials a SIP trunk from within a session: consultations, telehealth visits, embedded demos, SIP-bridged contact-center calls. Each becomes a row with its session-creation site, token-vending endpoint, archive consumer, and SIP-trunk endpoint. Gate exit: every row names an Orbit room kind (scheduled or ad-hoc) and a grant tier per participant class.
  2. Smoke window on one flow. Port one low-risk flow end-to-end while Vonage stays live for the rest. Create the Orbit room alongside the Vonage session (both created server-side; the Orbit room is the shadow), mint Orbit join tokens for internal users, and run real sessions with your own team. Gate exit: recording lands on Orbit or your storage, webhooks fire into the shim, and the SIP trunk passes both the inbound and outbound dial paths for the flows that use them.
  3. Switch the receivers. Receivers are whoever joins last: customers, patients, guests. Move the guest-join link to the Orbit room while the agent path stays on the shadow Vonage session for the rollback window. Gate exit: receiver sessions complete on Orbit with no Vonage-side join in the last N days, and the rollback path is still warm.
  4. Reach telemetry parity. Before you decommission anything, prove the observability survives: join/leave webhooks feeding session analytics, QoS telemetry (video.participant.qos) feeding quality alerts, video.recording.degraded verdicts feeding recording QC, and the moderation events (video.participant.muted / kicked / banned) feeding your audit log. Gate exit: one full business week with parity dashboards green on both vendors, and the SIP trunk mirrored across both if you use it.
  5. Decommission Vonage. Delete the session-creation and token-generation codepaths, remove the OpenTok/tokbox JS from the bundle, revoke the project API keys, delete the SIP interconnect endpoints, and cancel the session callback URLs. Keep the webhook shim translating event names until the downstream rename ships on its own schedule. Gate exit: Vonage Video hits its last day in your inventory as a no-op.

A note on tenant-owned controls before go-live (they belong in gate 1's checklist, not as an afterthought): recording consent capture, session-history retention windows, and the participant cap are tenant-configurable on Orbit; set them on your own account as part of the rollout, and keep the Orbit vs Vonage Video head-to-head cells for the pricing and capability rows a buyer validates against.

Frequently asked questions

Does Orbit's video API cover what Vonage Video's SDK did?

Yes for the shipped core: in-browser rooms, per-participant publish/subscribe grants, screen share, recording, live broadcast, and a prebuilt embed; parity the comparison matrix credits to both products. Orbit then adds the shape Vonage Video never had on one account: agent co-browse, AI video avatar participants, and the voice/SMS/email channels a video session usually travels with.

What replaces the OpenTok session/token signing flow?

A server-side call to the join endpoint: POST /api/v1/video/rooms-scheduled/:id/join (or the ad-hoc variant), with participant_name, an optional ttl_seconds, and the grant tier. The response is self-describing: the token, the SFU websocket URL, the effective permissions grant, and the expiry, so your client never decodes a JWT.

Can I bring existing Vonage Video SIP trunks over?

Yes: re-point the SIP URI host to Orbit SIP endpoints, and re-run the inbound and outbound dial paths the same way they ran on Vonage's SIP interconnect. The numbered dial-in surface moves as a SIP trunk, not as a PSTN porting, so the port-in concern (where one exists) applies only if you want to bring the PSTN number itself.

How do I preserve my existing archives?

Download the available archives via the archive list per session, upload the files untouched to your own storage, and update the session-recording lookup resolver to the new object key. Re-encoding is not required because the container format is preserved; the migration moves files, it does not transcode them.

Can we run Vonage Video and Orbit side by side during the cutover?

Yes, that is the recommended shape. Create the Orbit room as a shadow alongside the Vonage session for one flow, move the receiver join link over while the rollback path stays warm, and hold decommission until join/leave webhooks, QoS telemetry, recording QC, and the SIP-trunk path run at parity for a full business week.

The takeaway

Vonage Video is one of the few vendor-of-record video products with a true RTC surface, so the runbook has to cover the real-time port most migration posts skip. Export sessions, archives, credentials, and SIP trunks through the Vonage REST surface; map the session/token/auth triplet to Orbit's server-minted join flow; re-host archives without re-encoding; re-point the SIP interconnect family to Orbit SIP; and cut over as smoke window, receivers switch, telemetry parity, decommission. The capability rows you are validating against live on the Orbit vs Vonage Video head-to-head, and the comparison registry anchors the capability matrix.

Migrating from Vonage Video to Devotel Orbit: session, archive, and SIP cutover runbook — Orbit by Devotel