Skip to main content

Outbound country allowlist

The outbound country allowlist is the hard “if it is not on the list, we will not send” rail for your SMS, messaging-channel, and voice traffic. You set it once on the organization record, and every outbound send that resolves to a phone destination checks it before dispatch. When the destination’s country is resolvable and not on your list, the send rejects with 422 COUNTRY_NOT_ALLOWED. When you have set no list, or when the destination cannot be resolved to a country, the send passes. This page is the concept guide: what the gate is, why it is deliberately yours and not the platform’s, and how to keep it honest over time. For the request/response schema see API Reference → Settings. For a send that rejected and you want the decision tree, see SMS destination blocks.
This control gates outbound destinations only. Checking an inbound origin is a different gate — see Inbound Country Gate. Nothing on this page makes Orbit a compliance regulator for your traffic: jurisdiction and content decisions stay yours.

1. Why there is no platform-global block

Orbit takes a deliberate stance on destination policy: the platform imposes no global country block of any kind, for any channel. There is no list of countries Devotel refuses on your behalf, no embargo rail folded into routing, and no default that decides a whole region is off limits before your sends get a chance. That stance is what makes this gate an opt-in device rather than a restriction you work around. Fraud teams at customers that fan out traffic (OTPs, wallet top-ups, API-driven senders) asked for one hard statement they can make to auditors and to their own engineers: “we do not send outside these countries, ever.” The country allowlist is that rail — it exists so the statement is enforceable, not merely written down. The upshot for a new tenant is that nothing is blocked until you block it; the upshot for a compliance review is that an explicitly-set list is a hard, enforced answer, not a dashboard preference.

2. The two settings

Two values under settings.fraud on your organization record decide the posture: Read and write them through GET / PUT /api/v1/settings/compliance/country-allowlist — the PUT upper-cases and dedupes codes before persisting, and owner role is required to write. allow_all_countries: true exists so the “we intentionally send anywhere” posture is a decision recorded on the org, not merely an empty list someone hopes nobody has set. When you see a confusing reject, check both fields; the checklist at the end of this page names this explicitly.

3. Resolution model — fail-open until you opt in

On a send, the gate resolves the destination to a country and then decides. The order matters and the defaults are always the open ones:
  1. Non-phone destination (an email address, a synthetic chat identifier): passes. The gate speaks phone channels only.
  2. Resolution fails (no confident country): passes. The gate never rejects on an unresolved input.
  3. allow_all_countries === true: passes. The explicit override short-circuits before the list is consulted.
  4. allowed_countries is empty or unset: passes. This is the fail-open default — a blank posture blocks nothing.
  5. allowed_countries is non-empty and the resolved country is on it: passes.
  6. allowed_countries is non-empty and the resolved country is not on it: hard reject, 422 COUNTRY_NOT_ALLOWED.
Codes are normalized to upper-case ISO-2 and deduped at write time, so the shape you read back is the shape the gate evaluates. 422 (rather than a more alarming 5xx) is deliberate: client SDKs should treat the reject as the “do not retry” class, parity with carrier blocklist rejects such as CHANNEL_BLOCKED_DESTINATION. The gate’s own lookup also fails open. If the settings row cannot be read at send time, the send proceeds — a database blip must not black-hole legitimate traffic, and the rest of the fraud chain (IRSF prefix blocks, velocity caps, wallet admission) still runs downstream.

4. The platform-global reading is advisory-only

There is one piece of platform-global behavior left in the gate, and it is deliberately non-blocking. When a tenant has no allowlist and no allow-all flag, destinations that resolve to a small set of high-risk or sanctioned regions would historically be denied by a bare default. That default is now advisory-only: the send proceeds, and a structured log entry records the country and the reason, so operators and auditors retain visibility without a platform-mandated block. The same posture holds for the OFAC-sanctions read, which runs in the gate’s chain for observability only. Both advisories exist to be read, not obeyed — the only thing that can hard-block a send on this path is your own explicitly-set allowed_countries list.
If you want the advisory destinations to actually block, you opt in by configuring the allowlist yourself; that restriction is then tenant-owned and enforced, because tenant-owned is exactly the class of control that is permitted to be hard.

5. How it composes with the fraud stack

The allowlist sits in the send chain alongside the other outbound protection rails, and it is deliberately placement-scoped, not a replacement for them:
  • IRSF prefix blocks stop known artificial-traffic prefixes. The allowlist is a coarser country-level rail; the two compose (a destination must survive both).
  • Destination blocklists on the messaging side are prefix- or carrier-shaped. The allowlist answers the “never leave these regions” policy a blocklist cannot express.
  • Fraud Shield risk tiers (see Fraud Shield) score a destination and apply flag / block mode. The Shield’s verdicts are about risk; the allowlist is about scope. A tenant with a hard “EU only” posture wants the allowlist; a tenant with a hard “watch these risky routes” posture wants the Shield. Most fraud-aware tenants want both, each catching what the other cannot.
Every one of those controls is tenant-owned and defaults open, for the same reason the allowlist is: Orbit keeps the ledger of what you decided, and enforces exactly that. The tenancy posture audit map places this gate on Plane B — tenant opt-in gates — with quiet hours, DNC/RND, and the attestation floors, and against the handful of platform asymmetries (the TCPA federal voice window and the emergency-routing rail) that sit on Plane A. When someone asks “is country policy platform- or tenant-owned?”, the answer is that the allowlist is Plane B, and nothing on Plane A blocks countries.

6. Posture checklist

Decide the policy first, then state it explicitly on the org, then keep the audit map current.
  1. Decide. Is there a hard “we do not send outside X” statement? If yes, set allowed_countries to the exact list. If no, set allow_all_countries: true so the open posture is recorded, not accidentally unset.
  2. State the posture on the org. Do not leave both fields empty unless blank-open is the intended answer; either the list or the override should carry your explicit decision.
  3. Compose with the other rails. Check the destination against prefix blocks and the Fraud Shield separately; the allowlist is one gate in the chain, not the chain.
  4. Keep the audit map current. Treat a flip of either field like any other Plane B toggle: it belongs in the toggle inventory review, and the posture audit map should show your current entry.
  5. Interpret a reject. 422 COUNTRY_NOT_ALLOWED with a configured list means the system did what you asked. If the reject surprises you, walk SMS destination blocks before adding a country.