Quick answer: In a regulated market, nothing you filed yesterday lasts forever — a carrier or regulator wants proof of who you are before a phone number activates or a Sender ID carries traffic, and that proof expires on a schedule the regulator set, not yours. Devotel Orbit models that proof as a loop you run, not a gate it imposes: look up the country's requirements with GET /compliance/country-rules, upload each document once into a tenant library where it gets a doc_… ID, bind the documents to a compliance profile (cprof_…), file the Sender-ID registration referencing those IDs, and run the go-live checklist. This playbook walks the loop end to end across Brazil (ANATEL), the UK (OFCOM Sender-ID pre-registration), and India (TRAI DLT), then shows how to keep the expiry watch alive in CI with GET /compliance/health and the document-expiry alerts endpoint. Every control here is tenant-owned: you file, the platform carries the filing to the carrier and reports the review status back.
Step 1 — Read the country rules before you gather anything
The mistake that costs operators weeks is assembling documents first and reading the country's rules second. The rules differ per country and per channel — Brazil's SMS sender rules answer to ANATEL while WhatsApp in the same country answers to Meta's WABA rules — so the first call of any launch is the read-only regulatory reference:
curl "https://api.orbit.devotel.io/api/v1/compliance/country-rules?channel=sms" \
-H "Authorization: Bearer $ORBIT_API_KEY"Each row in the response is one country × channel, and three fields decide your next move:
registration—none(send freely),recommended(send now, register for delivery stability), orrequired(traffic is blocked at the send gate until you have an approved registration). This one field is the launch gate.sender_types— which "from" identities the country accepts:alphanumeric,long_code,short_code,ten_dlc,waba,rcs_agent, and so on. Pick from this list, not from habit.content_restrictionsandstop_requirement— consent rules and the mandatory opt-out keyword, in the language the country demands.
The rows ship with a last_synced_at timestamp from the platform's upstream regulatory feeds, so you are reading a freshness-stamped reference, not a frozen blog table (this post included — always let the endpoint answer, not the page). Where registration is required or recommended, the same loop continues: you will need documents, a profile, and a filing. Where it is none, you still owe the content and STOP rules.
Step 2 — The documents-KYC loop: upload once, reference by doc_… ID forever
The document library is tenant-wide and separate from any single profile. The discipline that makes it work: upload the `doc_…` first, reference its ID later — no endpoint in the compliance family accepts a raw file.
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/documents \
-H "Authorization: Bearer $ORBIT_API_KEY" \
-F "type=business_registration" \
-F "country_code=BR" \
-F "file=@/path/to/cnpj-registration.pdf"The response hands back a library ID that always starts with doc_. Accepted types run from business_registration and tax_id-style certificates through id_card, passport, utility_bill, and proof_of_address; accepted formats are JPEG, PNG, WebP, and PDF, up to 10 MB. Files are encrypted before they leave the API and held in private storage, and a doc_… ID is not guessable or shareable outside your organization.
That ID is now a durable pointer. The same doc_… can back a Brazilian Sender-ID filing today and a UK one tomorrow, playing a different role in each profile. Three product surfaces read the same pointer:
- Compliance profiles — attach the document to a profile with a role (
id_proof,address_proof,business_doc,authorization). - Sender-ID registration — each country filing carries
document_refs: the list ofdoc_…IDs backing that market. The registration route never accepts files; it references what you already uploaded. - Regulatory preview and number purchase —
GET /numbers/regulatory-previewreturnscompliance_profile_satisfies: trueonly when the profile's required fields are complete and its attached documents are non-expired. Buying a number without a satisfying profile lands it atpending_compliance— debited, but not activating until the profile is attached.
Expiry is part of the loop, not an afterthought. Regulators treat documents as stale after a fixed age — the UK's OFCOM-backed regimes, Germany's BNetzA, and France's ARCEP among others generally require ID or address proof no older than three to twelve months — and Orbit records an expires_at per attached document. Renewal is a fresh upload: upload the replacement, attach it in the same role, detach the expired one. A profile already approved stays approved while you swap; the submission is re-reviewed on next use.
Step 3 — The compliance profile: one identity bundle, one lifecycle
A compliance profile (cprof_…) is one regulatory identity bundle: who the end user is, for which use case, in which country. Carriers review it as a unit — approve once, and every number or sender it covers can lean on it.
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/compliance-profiles \
-H "Authorization: Bearer $ORBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "BR + GB alpha sender — Acme Ltd",
"use_case": "sms_sender_id_alphanumeric",
"country_code": "GB",
"countries": ["GB", "BR"],
"end_user_type": "business"
}'Set the structured fields the country asks for (registered business name, address, tax ID) with PUT /compliance-profiles/:id/data, attach the documents you uploaded with POST /compliance-profiles/:id/documents passing document_id and role, then submit. The profile status moves draft → pending_review → approved (or rejected), and eventually expired when its validity window closes. Only an approved profile satisfies a country's checks.
Two operational rules keep the lifecycle clean:
- Check which fields a country requires before you fill them — the regulatory-preview endpoint names the required fields per country, so you never guess the schema.
- Watch expiry from the BI surface, not from a calendar —
GET /numbers/document-expiry-alertsderives alerts from the timestamps Orbit already stores (expires_atper document, carrier verify-by deadlines), returning each alert withearliest_expiry_at, a whole-days countdown (negative once lapsed), and asuggested_actionofreneworrenew_or_release. The look-ahead window defaults to 30 days and is tunable per organization, so feed it to a dashboard and renew with lead time instead of finding out from a failed send.
Step 4 — Sender-ID registration: reference the library, never re-upload
With an approved profile and live documents behind you, the Sender-ID filing itself is small: per country, you submit the sender name, the use case, and document_refs — the doc_… IDs you already hold. The same document backs every country that accepts it. Final approval is granted by the carrier or regulator in each country; Orbit carries the filing and reports the per-provider review status back to you, but the decision is never the platform's.
Brazil (ANATEL), UK (OFCOM pre-registration), India (TRAI DLT): three filing shapes
The loop is the same everywhere; what changes is who approves and how long the queue is:
- Brazil — ANATEL-carrier registration. Alphanumeric Sender IDs file through the carriers under ANATEL's supervision; plan on a business-registration and use-case document set, and budget days of review. The same country's rules row for SMS shows a separate WhatsApp row answering to Meta's WABA rules — one country, two filings.
- United Kingdom — OFCOM-backed Sender-ID pre-registration. UK mobile operators pre-register alphanumeric senders against known-fraud lists; expect the business-identity document set plus brand-ownership proof, and note the document-age windows: address or ID proof older than the accepted three-to-twelve-month band is the most common UK rejection reason, which is why the expiry watch (Step 3) belongs in the loop, not in a runbook you read once.
- India — TRAI DLT, a different regime entirely. India does not use the generic Sender-ID flow at all: every sender ID ("Header"), content template, and consent template registers through the national DLT portals under TRAI. The
country-rulesrow for India points you there; on Orbit the DLT header-to-sender linkage is what makes a registered Indian header usable for sending. Treat India as its own checklist, not as a row in the generic one.
The US and India are the two special regimes (10DLC and DLT); every other market runs the generic loop with country-specific paperwork.
Step 5 — The go-live checklist, and why bundles provision drafts only
Before traffic, run the checklist in order:
country-rulesread:registrationunderstood (none / recommended / required),sender_typespicked,content_restrictionsandstop_requirementsatisfied.- Documents uploaded to the library,
doc_…IDs recorded, none inside its expiry window. - Profile complete: required structured fields set, documents attached with roles, submitted, and
approved. - Sender-ID filing submitted per country with
document_refs; review status tracked per provider until approved. - Opt-out keyword present in the template, in the language
stop_requirementnames. - Expiry watch wired:
document-expiry-alertspolled on a schedule.
Orbit's vertical bundles (the industry packs in the compliance plugin marketplace) encode exactly this checklist — and they provision drafts, never live resources. Activating a bundle creates a draft compliance profile, draft campaign templates, and a draft agent, and records the go-live checklist on the profile. Nothing is wired to a carrier on activation; you review the drafts, fill the country-specific fields, and submit when you are ready. The drafts-forever shape is deliberate: a bundle can prepare the filing, but only you can file it.
Step 6 — Keep the loop alive in CI: GET /compliance/health
Filing is not the end of the loop — the score carriers act on changes with traffic. Orbit's compliance health surface is read-only and CI-friendly: it never blocks a send, so you can call it from a scheduled job and fail your own pipeline on the thresholds you choose.
curl "https://api.orbit.devotel.io/api/v1/compliance/health?window_days=30" \
-H "Authorization: Bearer $ORBIT_API_KEY"The response is a 0–100 score with a risk band (healthy / watch / at_risk / critical) plus a warnings array, each entry carrying a human-readable message and recommendation. The score blends four carrier signals — consent coverage, opt-out velocity, STOP-reply rate, and carrier-rejection share — weighted 30/15/25/30, and a single critical factor floors the band at at_risk regardless of the average, because carriers act on the worst signal, not the mean. Per-sender and per-campaign variants (/compliance/health/numbers, /compliance/health/campaigns) let a nightly job page on the worst sender rather than the org average. Pair it with document-expiry-alerts and you have the two halves of revisiting expiry: documents about to lapse, and traffic about to draw carrier attention — both before either costs you delivery.
The residency and per-country document checklist
Keep this beside the runbook:
- Residency is scoped, not global. Countries enable per tenant — a row in
country-rulesmeans the market exists in the reference, not that it is live on your account. Coverage, the documents you filed, and the profiles are all yours; nothing about filing in one market files you into another. - The document set most markets ask for: proof of business registration; a use-case description; brand ownership or authorization; a local tax or regulator ID. Add ID-and-address proof for individual end users.
- Expiry ages differ by regulator — plan renewals against the strictest market you file into (3–12 months is the common band), not the laxest.
- Two regimes are special: India (DLT portal — headers and templates) and the US (10DLC — brand plus campaign). Everything else runs the generic loop with local paperwork.
- Approval is external by design. The platform stores, carries, and reports; the carrier or regulator approves. Build lead time into launch plans accordingly.
The whole reference — endpoint schemas, profile fields, and per-country rules — lives in the compliance docs. Run the loop once per market, keep the expiry watch on, and filing stops being the launch blocker it is on most platforms.