Skip to main content

Import and migration lifecycle

The one-click migration importer moves your existing configuration and audience out of an upstream CPaaS or customer platform and maps it onto your Orbit tenant. This page explains the lifecycle of an import end to end — what each wizard step does, what states an import job moves through, how the dry-run preview builds its conflict list and ETA, and what happens to your credentials while a job runs. The exact request and response shapes live in the Imports API reference and the Imports endpoints reference; this page is the model underneath them.

What the importer is

Every import runs the same five-step wizard, regardless of source:
  1. Connect. You authorize Orbit to read your upstream account — an OAuth flow where the upstream offers one, or a pasted API key. Orbit exchanges that authorization for an opaque, encrypted envelope and never echoes the raw secret back to the browser.
  2. Preview (dry run). Orbit reads the upstream account at your chosen scope and returns estimated row counts per entity kind, the conflicts it already knows about, and an ETA — without writing anything. You can run the preview as many times as you like; nothing lands until you confirm.
  3. Run. Confirming creates an import job in pending and hands the work to a background queue worker. The wizard returns immediately; the import runs to completion outside the request.
  4. Progress. A live stream (server-sent events) and a polled list view report per-entity counts — imported, skipped, failed — as the worker advances through each entity kind.
  5. Reconcile. Anything that collided with data already in your tenant is collected as a conflict list. The final wizard screen lets you review each collision and the policy that was applied to it.
Because every upstream source implements the same adapter behind this contract, the wizard behaves identically whether you are coming from a messaging API or a marketing platform — only the connect method and the entity list differ.

Supported sources and entity kinds

The importer ships with five upstream sources. Each advertises the subset of entity kinds it can pull, which is what the wizard offers as selectable checkboxes after you connect: Two mapping rules are worth knowing before you run:
  • Audiences map onto Orbit segments. Klaviyo lists (static audiences) and segments (dynamic, rule-based audiences) both land as segment definitions on the Orbit side; imported contacts reference them.
  • Imports are read-only on the upstream. Pulling phone numbers, profiles, or messaging services into your tenant never routes traffic through the source. Outbound voice and SMS from Orbit always exit through Orbit’s own carrier infrastructure — an import cannot redirect it.

The import-job state machine

Each confirmed run is persisted as one import job with a single current status: succeeded, failed, and cancelled are terminal: a job in any of them never moves again, and cancelling one of them is rejected rather than silently re-applied. Only pending and running jobs accept a cancel.

Preview semantics: the dry run

Calling the preview endpoint is always a dry run — it reads the upstream account and returns a projection without creating a job or writing a single row. For each entity kind you selected, the response carries:
  • estimatedCount — the projected number of rows in the upstream account at the current scope.
  • knownConflicts — collisions Orbit can already see on its side (for example, phone numbers from your selection that are already claimed in your number pool).
It also carries an etaSeconds estimate. The ETA is deliberately pessimistic rather than optimistic: it assumes the background worker’s steady page-through rate and is driven by the per-source published rate-limit budget (for example, Twilio’s REST budget allows far more requests per minute than Front’s per-teammate token, so the same account size yields a longer ETA on Front). A large Klaviyo audience, likewise, is paced to the most restrictive endpoint that import touches, so a flows-heavy account does not trip the upstream’s rate limiter mid-run. Treat the number as “how long can this take at worst,” not a promise. Because the preview response is timestamped at generation, re-run it if your upstream account has moved since you connected.

Credentials at rest

Credentials enter and leave the pipeline under one rule: encrypted at rest, decrypted only at the point of use.
  • On connect, the raw credential is encrypted immediately and carried from then on only as an opaque envelope string — through the wizard, onto the job record, and into the queued job payload.
  • The only component that ever decrypts the envelope is the import worker, at boot, to read from your upstream account. Neither the API response, nor the job list, nor the progress stream ever returns the credential.
  • When the job reaches any terminal state — succeeded, failed, or cancelled — the stored envelope is wiped from the job record. Orbiting the lifecycle this way means your old provider’s secret lives in Orbit’s database only for the lifetime of the job that needed it.
  • A stored envelope is also validated against the expected credential shape when it is read back, so a hand-edited or half-written job record is rejected rather than misrouted into the wrong auth flow.

Conflicts, cancel, and rollback

Every collision the worker hits — for example, a phone number that already exists in your pool, or a contact that matches one already in your tenant — is recorded as a conflict entry with the policy that was applied to it. You choose that policy per entity kind before running: skip (leave your existing record, ignore the upstream copy), overwrite (replace your record with the upstream copy), or merge (combine fields). The conflict list on the finished job is what the wizard’s reconcile screen renders, so nothing collides silently. Three operator actions bound the lifecycle:
  • Cancel. pending or running jobs can be cancelled; already-terminal jobs return a conflict response carrying their current status, so the wizard can say “Already completed” or “Already cancelled” without a second lookup.
  • Idempotent create. Re-submitting a run for the same job id is a no-op on the record, so retried submissions or double-clicks never fork two parallel imports of the same job.
  • Rollback. A terminal job can be rolled back: every contact the import created (each row is stamped with the job that created it) is deleted, and the job records how many rows were removed. A running job must be cancelled first, and a job that was already rolled back refuses a second one.

See also