Skip to main content

Assemble your STIR/SHAKEN attestation posture

This guide is the walkthrough form of the STIR/SHAKEN attestation posture concept page: it assembles the posture in the order the resolver applies it, with worked curl calls at every step. The hard problem — landing at attestation level A on your outbound numbers — is not one toggle. It is six small surfaces working in the right order. Run the steps top-down; steps 1–4 raise the level your traffic signs at, steps 5–6 make the resulting posture visible, and the troubleshooting hooks at the end close the loop when reality doesn’t match the posture you chose.
Attestation posture is tenant-owned. You choose the target level, the downgrade handling, the inbound floor, the delegate-certificate coverage, and the branded-calling configuration. Orbit records and enforces what you set; it does not mandate a posture, and the carrier of record never signs higher than the platform attests. Regulatory judgment about which level a given calling programme must hold stays with you and your counsel. Nothing on this page is legal advice, and no step gates, blocks, reroutes, or re-signs a call.

How the parts fit

Before the steps, the model in one picture: Signing itself never happens on Orbit. The platform signals the resolved level on the outbound INVITE; Devotel’s wholesale softswitch — the carrier of record — signs the PASSporT at exactly the level the platform signals. For the full signing model, see STIR/SHAKEN attestation.

Step 1 — Resolve ownership first (the A/B/C ladder)

The dial-time resolver walks a fixed ownership order, before any policy is consulted:
  1. Owned number → A (full). A caller ID that is an active number your organization owns through Orbit — purchased on-platform or ported in and billed to your org — attests at A. This is the only path to full attestation.
  2. Leased pool number → B (partial). A pool number with an active assignment to your org attests at B. Orbit authenticates your org, but pool ownership is not your verified right-to-use.
  3. Anything else → C (gateway). A verified external caller ID, a hosted or BYON number you control but do not own in Orbit, or an unattributable caller ID attests at C — the weakest signal and the one downstream carriers most often label “Spam Likely.”
When a caller ID matches more than one arm, the stronger attribution wins — a number the org owns outright attests A even if it also rides an active pool lease. Read { "source": "owned" | "leased" } off the posture snapshot next to the level calls from that number actually attest at — the snapshot is the truth source, not your intuition about what the org holds. No step on this page substitutes for Step 1. If answer rates matter, steps 2–4 refine the posture for numbers the org already owns or legitimately controls; they never leapfrog a non-owned number to A.

Step 2 — Run the delegate-certificate lifecycle (BYON: C → B, never A)

A delegate certificate (ATIS-1000092) is the artifact your service provider hands you to authorize specific numbers you control but do not own in Orbit. Registering it with Orbit raises the covered numbers from C to B — partial, never full. The ceiling is deliberate: the certificate is a tenant-supplied artifact, Orbit does not cryptographically validate its chain, and the covered-number list you record is free-form input not bound to the certificate’s real TNAuthList — so B (“customer authenticated, number authorization not provider-verified”) is the correct rating for that evidence. A self-registered artifact must never be able to spoof full attestation.

Register a certificate

Obtain the PEM chain from your provider, then register it with its coverage list and validity window:
At least one covered number or range is required (it is the TNAuthList you record). Numbers are E.164; ranges are inclusive on both ends with start <= end. Write-time failures are precise:
  • 422 INVALID_CERTIFICATE — no parseable PEM certificate block in certificate_pem (wrong encoding, truncated chain, or a non-certificate payload).
  • 422 INVALID_COVERAGE_RANGE — a range had start > end.
  • 422 VALIDATION_ERROR — a malformed field (non-E.164 number, invalid timestamp).
  • 409 DELEGATE_CERT_DUPLICATE — the same chain fingerprint is already registered; the numbers already attest at its level.
  • 409 DELEGATE_CERT_LIMIT — the 50-certificates-per-org cap is full; revoke an unused certificate first.

Watch the effective status, not the submission time

The registry derives each certificate’s effective status live: A certificate that flips to pending, expired, or revoked stops covering its numbers, and those numbers fall back to their ownership-based level at the next call — with no call blocked and no error emitted. Read the registry with:

Renew before the window closes

Re-register a renewed chain before the current certificate’s not_after passes — the drop happens at the flip, not after it. Revoke a certificate you no longer control with:
Revocation is immediate and cannot be undone; the record is kept with a revoked-by line for audit. Do not re-register a revoked certificate’s chain — obtain and register a fresh one. Certificate writes are owner/admin gated; certificate reads are not.

Retirement is ownership

A delegate certificate is the gap-fill, not the destination. The permanent fix for a covered number is porting it into Orbit (Step 1): once ownership settles, the coverage is redundant and the certificate can be revoked.

Step 3 — Set the inbound verification floor (per-DID policy)

Inbound calls arrive with STIR signalling (a pre-verified Verstat result, or a raw Identity header), and Orbit parses it. Two floors apply:
  • Org-level — inbound_min_verification (Step 5) decides which inbound signature levels count as verified in your posture snapshot. Reporting only; it never rejects a call.
  • Per-DID minimum attestation on the inbound route is the hard floor: when a route’s minimum attestation is set, inbound calls whose parsed level falls below it are declined with SIP 603 before routing.
Manage the per-DID route with the inbound-routing surface:
The floor levels are A, B, or C. Because the resolver treats unsigned inbound (unknown) as below any letter floor, setting the per-DID floor rejects unsigned callers as well as ones that simply failed signing — leave the floor unset (the default) to admit any signed call regardless of level, or set it only on DIDs where you deliberately want the stricter posture. A rejected inbound call carries a readable 603 Decline reason and rejection is observable per call, before any media path opens.
The per-DID floor applies to inbound only. It never affects outbound attestation, outbound routing, or outbound signing — those resolve in Steps 1–2 and the policy in Step 5.

Step 4 — Wire branded calling (RCD) with a CNAM fallback per DID

Rich Call Data (RCD) is the STIR/SHAKEN extension that renders your verified brand on the recipient’s handset — display name, logo, and reason-for-call — on A-attested calls only. Delegates at B, and unattributed C, never carry it. RCD is the posture’s payoff surface: the handset treatment that actually lifts answer rate on owned numbers.

Org-level configuration

Set the org default (owner/admin) — the same surface as Settings → Voice → Branded calling:
Validation at write time:
  • display_name is 1–40 characters (carriers truncate longer at the wire).
  • reason_for_call is up to 60 characters (the strictest downstream cap).
  • logo_url must be a public, TLS-served, stable PNG/JPEG/WebP URL — no authentication headers, no http://, no internal hosts. An out-of-spec URL is a 422, not a stored-and-later-failing config.
  • holdout_pct (optional, 0–50) withholds RCD from that fraction of otherwise-branded calls to measure answer-rate lift honestly — a randomized control, not a before/after. Omitting it leaves a running experiment untouched.
A save that changes any rendered asset (name, logo, reason) resets the brand-verification state to unverified — the revised brand re-enters review before it renders again. Toggling enabled or adjusting holdout_pct alone does not reset the verdict.

Per-DID override and the CNAM fallback

The org-level brand paints every outbound number; a per-number profile on the DID overrides the org default for that one number, so a multi-brand fleet can carry a caller’s brand only on their numbers. The override precedence:
  • Profile enabled and fully specified (name + logo) → the profile assets render.
  • Profile disabled or incomplete (missing name or logo) → the org default renders, unchanged.
  • Carrier not registered → RCD drops silently for that call; the recipient sees plain attestation plus any CNAM name on file. That CNAM record is the fallback label, not a second brand.
Register the per-DID calling name with CNAM so the fallback is never bare:
See CNAM & caller ID for the LIDB/dispatch lifecycle. The fallback hierarchy therefore reads:
  • RCD renders — verified brand on the handset.
  • RCD not carried (non-A attestation, unregistered carrier, incomplete profile) — plain attestation result, plus the CNAM name if one is registered.
  • No CNAM either — the bare number, and the spam-likely treatment downstream carriers hand generic traffic.
For the full RCD surface — the holdout experiment, the per-carrier registration list, and the failure modes — see Branded calling.

Step 5 — Set the reporting policy (target level, downgrade handling, reporting floor)

The org-level attestation policy declares what you intend (target level), what to do with below-target traffic (downgrade handling), the inbound signature floor treated as verified for fraud posture, and whether failed/unsigned inbound calls count as spoof-risk. It never gates a call — it drives the posture snapshot’s measurement.
Writes are partial — a write that names only target_attestation leaves the inbound floor and the spoof-risk flag untouched. Reads (GET /compliance/attestation/policy) always return 200 with a complete policy object; an org that has never set one gets the safe defaults. The intent field here is the one a tenant sets on the dashboard surface (Settings → Compliance → Attestation) or over this endpoint — always the same store either way. Invalid values are a 422 and every successful write lands in your audit log. Owner/admin can write; any member can read.
The policy is reporting intent, not a gate. Setting a target while your traffic runs on leased pool numbers (B) does not raise or lower what gets signed — the softswitch signs at exactly the level the platform attests, and your posture snapshot simply starts flagging those numbers as below target. Do not PUT a higher target hoping the level follows; the level follows ownership (Steps 1–2).

Step 6 — Read the posture snapshot

GET /compliance/attestation/posture is the read-only measurement you assemble everything against. It answers the two questions this guide is built around at once:
  • originating.numbers[] lists each originating number with the level calls from it actually attest at (owned → A, leased → B), and meets_target compares that to your Step-5 target. The list caps at 500 numbers (numbers_truncated tells you when you hit the cap) so a sender with thousands of DIDs sees totals first and specific held-back identifiers next — not an aggregate hiding the offender.
  • inbound.summary classifies the last 30 days of inbound calls to DIDs your org currently owns: signed at-or-above the floor → verified; signed-below-floor or off-net → unverified; failed or unsigned → spoof_risk when the flag is on, else unverified. verified_rate is the verified share of all inbound calls, or null (not zero) when the window had no inbound traffic.
Both halves are org-scoped: originating rows come from your own numbers and assignments only, and inbound counts calls that arrived on a DID your org currently owns — a released DID reassigned to a new owner starts that owner’s inbound history clean. Reads fail soft: if an underlying lookup is unavailable, the affected half returns empty or zeros rather than failing the whole snapshot. Recheck the snapshot after any Step-1-to-5 change — the posture posture confirms the change the way a diff confirms a patch, and an unreconciled snapshot is exactly the case Step 7 works.

Troubleshooting hooks

When the snapshot or the recipient-side treatment disagrees with what you declared, two guided pages pick up from here rather than re-explaining the build:
  • STIR/SHAKEN attestation downgrade — the systematic root-cause run for a call that signs lower than your target: the C ceiling on non-owned numbers, an expired or mis-registered delegate certificate, a per-number branded override, and carrier coverage gaps in RCD — plus the fix run for each and the error-code map (INVALID_CERTIFICATE, INVALID_COVERAGE_RANGE, DELEGATE_CERT_LIMIT, DELEGATE_CERT_DUPLICATE).
  • STIR/SHAKEN never measured — the quick-start for a tenant who has never opened the surface: read the current policy defaults, put the inbound reporting fields back to the expected defaults (inbound_min_verification: "B", the flag on), and run the first posture measurement.

See also