Terraform model — Orbit resources as infrastructure
Terraform’s model is simple: declare the desired state of a resource, and the provider converges reality toward it. The Orbit Terraform provider applies that model to the CPaaS surface — webhook endpoints, messaging services, numbers, subaccounts, campaigns, and AI agents become HCL resources you version, review, and apply in CI. This page explains the model: what the provider is, which API surface it governs, and how plan/state semantics map onto the REST API. For copy-pasteable HCL and per-resource attributes, use the Terraform provider guide.What “Orbit as IaC” means
The provider is a thin wrapper over the official Orbit Go SDK. Its entire job is lifecycle framing:- One client. At provider-configure time it builds a single SDK client — one API key, one optional base-URL override — and hands that client to every resource.
- One schema per resource. Each resource declares a Terraform schema (required, optional, computed attributes) whose fields mirror the OpenAPI shape of the corresponding REST resource one-to-one.
- Verb mapping. Terraform’s four lifecycle hooks (Create, Read, Update, Delete) call the corresponding HTTP verb on the API path for that resource. No Terraform-specific magic exists anywhere — the provider sends exactly the requests you would send with the SDK by hand.
curl holds under
terraform apply, and every new API field the REST surface ships is a
candidate attribute rather than a new integration to build.
The resource inventory
Six resources cover the manage-as-code surface:
What is deliberately excluded, and why:
- Outbound voice and SMS termination. Carrier routing on Orbit is
owned by the platform softswitch — no Terraform resource sets an
outbound carrier, SIP trunk, or messaging route, and none ever will.
orbit_numbermanages inbound routing only. - Runtime actions. Campaign sending, agent invocation, live messaging — anything imperative — stays out of the declarative lifecycle. Terraform manages durable configuration, not runtime triggers.
- Nested agent internals. An agent’s tool registry and
knowledge-base bindings have their own surfaces;
orbit_agentmanages the portable agent config (name, prompt, model, generation settings) and deliberately stops there. - Read-most surfaces. Dashboard-only conveniences with no stable idempotent mutation surface (onboarding wizards, playground state) are not Terraform material.
The plan/state lifecycle
Everyterraform plan is a diff between three things: your HCL, the
last-known state, and a fresh read of the server. The mapping to the API
is mechanical:
Two mechanical rules fall out of this mapping:
- Computed fields converge to the server. Fields marked computed (server-assigned ids, server-defaulted flags) are re-read on every refresh, so the state file always carries what the API returns — not what HCL last said.
- Removed attributes are cleared explicitly. On update, attributes
the server treats as nullable are sent as explicit
nullwhen HCL omits them. Without that rule, deleting an attribute from config would silently leave the old value server-side. With it, the next apply brings the server back to exactly what config declares.
terraform import <addr> <id> recovers drift at the whole-resource
level: it fetches the resource’s current server state and captures it as
the state baseline. Import does not write HCL — run
terraform state show <addr>, copy the values into config, and the next
plan goes empty.
API key resolution — argument vs environment
The provider accepts two configuration inputs, and resolution order is argument-first:api_key is a sensitive attribute — Terraform masks it from console
output and state diagnostics. The CI-friendly pattern is to omit the
argument entirely and set ORBIT_API_KEY in the pipeline’s secret
store, so no key material sits in version control. base_url exists to
point the provider at a staging Orbit deployment; production needs
neither.
Drift-reconciliation semantics
Drift is any mutation made out-of-band — a dashboard edit, an SDK script, a support-console change. Reconciliation happens on refresh:- Planned refresh. Every
terraform planre-reads each managed resource viaGET, so a dashboard-side edit surfaces as a diff before you apply anything. - Config wins. When you apply, the diff is resolved in the direction of HCL — the provider PATCHes the drifted attributes back to declared values.
- Deleted server-side → removed from state. If a refresh gets a
404, the resource is dropped from state and the next plan proposes recreating it — destroy-and-recreate is explicit in the plan output, never silent. - Write-only fields cannot drift-check. Secrets the API never returns for reads (webhook signing secrets, subaccount API keys) are write-only by design: Terraform cannot detect out-of-band rotation of them. Rotate by updating the variable and re-applying.
- Force-replacement attributes. Where the API cannot mutate a
field in place (a number’s
phone_number, a subaccount’sslug), change means destroy + create. The plan names the replacement before approving.
terraform plan (or terraform plan -refresh-only) in CI to
turn drift from a surprise at apply time into a report.
Before the registry release — build from source
The provider is early access. Until the registry listing ships, its source of truth is the provider source tree, andterraform init cannot
pull a released binary. Locally:
dev_overrides in your Terraform CLI config at the built path) so
terraform init resolves the local build. Once the
registry.terraform.io/devotel/orbit listing publishes, the same
config works with no source build.
Where to go next
The Terraform provider guide is the operational companion to this page: full HCL examples, the per-resource attribute tables, and the drift-and import patterns walked end-to-end. This page explained the model; the guide shows the config.See also
- Provision Orbit resources with Terraform (guide)
- Go SDK — the SDK the provider wraps
- API keys, messaging, CCaaS & CDP
- Webhooks concept — delivery semantics