Skip to main content

Imports API

The one-click migration importer pulls your existing configuration and audience out of another provider and maps it onto Orbit. It runs as a five-step wizard: connect a source account, preview what will be imported (a dry run), run the import as a background job, watch its progress live, and reconcile any conflicts. Every credential you supply is used only to read your source account — phone numbers, messaging profiles, templates, contacts, conversations, and audiences. Orbit never sends messages or places calls through your old provider as a result of an import: outbound traffic always exits through Orbit. The credential is encrypted the moment you submit it, handed forward as an opaque envelope string, and removed from the job record once the import finishes. Base path: /api/v1/imports Authentication: Clerk session (Authorization: Bearer <token>) or API key (X-API-Key). Every endpoint requires an authenticated tenant.

Supported sources

The {source} path segment on the dry-run and run endpoints is one of:

Entity kinds

Each import selects a subset of entity kinds to pull. Every source advertises the kinds it supports; ask for between 1 and 10 per import. phone_numbers, messaging_services, templates, contacts, conversations, channels, flows, inboxes, tags, teammates, lists, segments

Step 1 — connect a source

The connect step exchanges your source credentials for an opaque, encrypted envelope string. You pass that envelope to the dry-run and run steps; it is never stored in the browser and the raw secret is never echoed back.

Start the Twilio Connect authorization

GET /api/v1/imports/twilio/connect
Begins the Twilio Connect OAuth flow. Returns a Twilio authorization URL for the wizard to open in a popup, plus a state value to match against on the callback.
cURL
200 OK
Returns 503 TWILIO_CONNECT_NOT_CONFIGURED when Twilio Connect is not enabled on the environment — fall back to Submit Twilio credentials manually below.

Complete the Twilio Connect authorization

GET /api/v1/imports/twilio/callback
Twilio redirects the browser here after the user approves access. It validates the returned state, exchanges the authorization code for credentials, encrypts them, and issues a 302 redirect back into the import wizard with the envelope attached to the URL. You do not call this endpoint yourself — Twilio invokes it, and the raw access token is never returned to the browser. Returns 400 when the authorization was denied or the code/state is missing or invalid.

Submit Twilio credentials manually

POST /api/v1/imports/twilio/manual-credentials
Use this when the OAuth flow is unavailable (for example, a self-hosted subaccount). Returns the encrypted envelope directly.
string
required
Twilio Account SID — starts with AC followed by 32 hex characters.
string
required
Twilio Auth Token, 8–256 characters.
cURL
200 OK

Submit Telnyx / Klaviyo / MessageBird credentials manually

POST /api/v1/imports/telnyx/manual-credentials
POST /api/v1/imports/klaviyo/manual-credentials
POST /api/v1/imports/messagebird/manual-credentials
These providers don’t publish an OAuth delegation flow, so you supply an API key directly. All three take the same body and return the same envelope shape.
string
required
The provider API key. Telnyx V2 keys start with KEY; Klaviyo private keys start with pk_; MessageBird access keys are alphanumeric (optionally prefixed live_ or test_).
string
Optional display-only label shown in the wizard’s “Connected as” line. Up to 128 characters.
cURL
200 OK
Returns 422 VALIDATION_ERROR when the key doesn’t match the provider’s format.

Step 2 — preview (dry run)

POST /api/v1/imports/{source}/dry-run
Counts the upstream entities and detects conflicts with data already in Orbit, so you can show an accurate row count and estimated duration before committing. Nothing is written.
string
required
The encrypted credentials envelope from step 1.
array
required
1–10 entity kinds to preview (see Entity kinds).
integer
Twilio only — how many days of conversation history to include, 1–90. Twilio exposes at most 90 days of message history without an Insights subscription, so values above 90 are rejected.
cURL
200 OK

Step 3 — run the import

POST /api/v1/imports/{source}/run
Queues a background import job and returns its jobId. Submit the same envelope and entities you previewed, optionally with a per-entity conflictPolicy.
string
required
The encrypted credentials envelope from step 1.
array
required
1–10 entity kinds to import.
integer
Twilio only — conversation lookback window, 1–90 days.
object
Optional map of entity kind → how to resolve a collision: skip, overwrite, or merge. Kinds you omit fall back to skipping conflicting rows.
cURL
202 Accepted
Open the progress stream for jobId to watch it run.

Step 4 — track progress

Stream import job progress

GET /api/v1/imports/{jobId}/progress
A Server-Sent Events stream of the job’s per-entity counts and status transitions. The first frame is a snapshot of the current state, so a page that subscribes late renders immediately; keepalive comments arrive every 15 seconds and the stream closes automatically after one hour. A job that has already finished replays its final end frame and closes. Frame events: snapshot, progress, status, end.
cURL
Returns 403 when the request origin isn’t allowed, or 404 when no such job exists for your tenant.

Get an import job

GET /api/v1/imports/{jobId}
A point-in-time snapshot of a single job — its source, status, and per-entity progress. Poll this if you don’t need the live stream.
cURL
200 OK

List recent import jobs

GET /api/v1/imports
Returns your organization’s recent import jobs, each with its source and status — used to render the import history table.
cURL
200 OK

Step 5 — cancel or roll back

Cancel a running import job

POST /api/v1/imports/{jobId}/cancel
Requests cancellation of an in-flight job. The status flips to cancelled and the worker stops between pages on its next check. Only a job that is still pending or running can be cancelled.
cURL
Returns 404 NOT_FOUND when the job doesn’t exist, or 409 IMPORT_NOT_CANCELLABLE (with the current status in details.current_status) when the job has already reached a terminal state.

Roll back a completed import

POST /api/v1/imports/{jobId}/rollback
Deletes every contact created by this import batch in a single transaction and records the rollback on the job. This is destructive and is restricted to owner or admin roles. Roll back only after the job has finished or been cancelled.
cURL
200 OK
Returns 403 FORBIDDEN for a non-owner/admin caller, 404 NOT_FOUND when the job doesn’t exist, and 409 when the job is still running (IMPORT_STILL_RUNNING) or has already been rolled back (ALREADY_ROLLED_BACK).

Errors

See also