Country rules enumeration model
The country-rules register answers one question per destination: “what does this country demand of a sender on this channel?” The answer is never a single country record — it is one row per (country code, channel), because per-country rules are per-country per-channel facts. Brazil’s Anatel rules govern SMS; Meta’s WABA policies govern WhatsApp; the two do not overlap, and a single “Brazil rule” would falsely merge them. This page covers the enumeration shape, the per-field enums the row exposes, and how the rows feed the send-time gate in the policy scan pipeline.The register is a global, ops-curated reference map — you and every
other tenant read the same rows. Every decision the rows inform — whether
to launch into a market, which sender type to register, what to put in your
country’s compliance pack — stays tenant-owned. Orbit curates the
reference; you select the posture. This page is not legal advice.
1. The enumeration shape — six channels, one row each
The register is keyed by(country_code, channel) — ISO-3166 alpha-2 plus
one of six supported channels. A country that matters to your launches has up
to six rows, and each row stands alone:
Read the enumeration through
GET /api/v1/compliance/country-rules?channel=<channel> — the channel
query parameter (default sms) selects the lane, and an optional region
parameter narrows the set. The dashboard console at Settings → Compliance →
Country rules renders the same list one channel tab at a time, so what you
read on screen is the same enumeration your integration reads over the API.
Provenance rides each row. Feeds (Telnyx country coverage, the MEF and GSMA
sender-ID registries, iconectiv for US 10DLC, Meta’s WABA catalog, the ITU
regulator index) stamp last_synced_at; an ops hand-edit stamps
last_reviewed_at — and a refresh never overwrites the free-text fields ops
curated. sync_source names the last feed that touched the row, so a “Synced
from MEF; reviewed by ops two days later” reading is reconstructable row by
row.
2. What one row carries — field by field
Each row exposes a fixed field set. Five of them are closed enums — the actionable ranges, not free text — and the rest are curated strings:
The closed enums are the part to trust mechanically — plan registration work
against
registration, plan receipt handling against dlr_support, plan two
way flows against two_way. The curated strings demand a read before the
first send into the country; they carry the nuance no enum holds.
3. Where the rows meet the send — the gate stays conservative
Two of the enum fields feed the pre-send scan directly. When a send has resolved to a single destination country, the pre-send pipeline passes that country’s row for the send’s channel into the policy scanner, and the scanner’s country gate evaluates the row against the send’s resolved sender type and registration state:- The send’s resolved sender type is checked against the row’s
sender_types[]— but only when both sides are explicit. An emptysender_typesarray, or an unresolvable sender type, means the sender-type half of the gate is skipped. - A
registration: "required"row can flag a send from an unregistered sender;recommendedandnonenever block.
- Uncatalogued countries are never blocked. No row for the resolved (country, channel) — or no single destination country resolvable — is a zero-violation pass.
- No recorded restriction is not a deny. An empty
sender_typesskips the sender-type half rather than failing the send. - Only explicit mismatches fire. The gate blocks on a recorded restriction the send actually violates; it never extrapolates one.
4. Reading the map for a launch — a worked enumeration
Before a first send into Brazil on SMS and WhatsApp, enumerate both channels explicitly rather than inferring one from the other:BR; the SMS row gives you the Anatel sender-ID
regime (sender_types, registration, sender_rules) and the STOP demand
(stop_requirement). Then repeat with channel=whatsapp — the WhatsApp row’s
sender_types: ["waba"] and registration posture come from Meta’s catalog,
not from anything the SMS row said. The two rows are deliberately separate
facts: the SMS plan you derive (sender-ID registration, throughput against
default_tps, DLR handling against dlr_support) and the WhatsApp plan
(WABA standing, two_way for conversational flows) each stand on their own
row, and a single merged “Brazil record” would have hidden exactly the
difference the launch needed.
Fold what you read into the country pack for the launch — pair it with your
quiet-hours window, campaign limits, and evidence binder per the
country rules console guide, and
re-read the row when a feed refresh stamps a newer last_synced_at.
See also
- Country rules console — walk the dashboard surface, fold a row into a country pack
- Policy scan pipeline model — where the country gate evaluates in the pre-send scan
- Omnichannel compliance matrix — per-channel control surface across the full matrix
- Outbound country allowlist — the tenant-owned counterpart gate (your list vs. the curated register)
- Quiet-hours preview — the per-channel window semantics that pair with per-channel country rules
- Country requirements — the jurisdiction-by-jurisdiction obligations catalog