Skip to main content

Troubleshooting: STIR/SHAKEN attestation downgrade

An attestation downgrade is the quiet answer-rate failure: the call connects, the routing is clean, and no error is returned anywhere — but the call leaves signed at C (gateway) instead of A or B, and downstream carriers label it “Spam Likely.” Answer rates collapse and the error-code catalog has nothing to point at, because a downgrade is not a refusal: there is no structured STIR/SHAKEN error code — the call still dispatches, signed at a weaker level. This page works the five root causes that produce a downgrade and the fix run for each. For what the attestation levels mean and where signing happens, see STIR/SHAKEN attestation; this page starts where that one ends — at a call that attests lower than you expected.
A downgrade never blocks a call. Attestation resolution fails open to C rather than failing the dial, and the policy flags below — target level, downgrade handling, certificate status — are reporting surfaces: they flag the gap, they do not gate traffic. Do not look for the failure in a blocked- call log.

Symptoms

  • Outbound calls arrive labeled “Spam Likely” on downstream carriers even though your dialing practices, traffic volume, and caller IDs haven’t changed.
  • Answer-rate drop on outbound campaigns with no other change in caller ID, list quality, or time of day — the signature of a level that silently fell from A or B to C.
  • Calls sign at C on numbers you used to reach A or B on — visible per call on the call record (the parsed attestation result is stored on every call), or across the org in the Attestation posture page.
  • Rich Call Data (branded calling) no longer renders on handsets that showed it before — often the same downgrade from the recipient’s side: RCD only attaches to A-attested calls.

Reads: measuring the downgrade before fixing it

Two reads tell you the downgrade is real and which numbers it covers. A posture snapshot is fine-grained enough to name the specific number — don’t work the fix runs below blind.

Originating: which numbers attest below your target

GET /compliance/attestation/posture lists every originating number with the level calls from it actually attest at, and compares that against your target_attestation:
How to read it for a downgrade:
  • originating.numbers[] — each originating number with the level it attests at (owned → A, leased → B) and meets_target against your declared target. A row with meets_target: false is a downgrade on that number; originating.summary.below_target counts them. numbers_truncated tells you when the 500-number list cap truncated the evidence.
  • policy.target_attestation — what you intend. If it’s A and your traffic runs on leased pool numbers (B) or BYON numbers (C), the below-target count lights up — that is the surface flagging the gap, not a blocked call.

Inbound: verification summary against your floor

The same snapshot carries the inbound half: inbound.summary classifies the last 30 days of calls arriving on your DIDs against your inbound_min_verification floor — verified share, spoof-risk count, and the verified_rate (or null, not zero, when the window had no inbound traffic). A drop in verified_rate or a spike in spoof_risk is the inbound-side signal worth reading before tuning the floor.

Root causes and fixes

Work the causes in order — the top two produce the spam-likely symptom on your own traffic; the bottom two produce it on the recipient’s handset even when the attestation level itself is fine.

Root cause 1: calling from a number you don’t own in Orbit (the C ceiling)

The dial-time attestation resolver mints A/B/C purely from ownership: a number your org owns through Orbit attests A, an active pool lease attests B, and anything else — a verified external caller ID, a hosted number, a BYON number you legitimately control but haven’t ported — attests C. That C is the “dreaded C ceiling”: no configuration raises a non-owned number to A. A is ownership-only, per STIR/SHAKEN attestation — and a delegate certificate (root cause 2) caps at B by design, because a self-registered certificate the platform doesn’t cryptographically chain-validate must never be able to spoof full attestation. Diagnostic. Pull the posture snapshot. The column that matters is source: a number showing attestation: "C" (or “B” against an “A” target) on a source the org doesn’t hold as owned is living under the ceiling. Fix run.
  1. Own the number. Purchase or port the numbers into Orbit (Number porting) so your org owns them outright. This is the only path from C to A. A delegate certificate covers the gap while the port completes (root cause 2), but the floor to A is ownership.
  2. Move your outbound traffic onto the owned DIDs. Until ownership lands, expect and accept a B target for BYON/leased traffic — or cover BYON numbers with a delegate certificate (root cause 2).
  3. Re-read the posture snapshot. The moved numbers now resolve to A, and meeting_target closes the below_target gap.
Do not PUT /attestation/policy a higher target and expect calls to sign higher: the softswitch signs exactly the level Orbit attests and no more — a worse-compared-to-target posture is a reporting flag, not a gate.

Root cause 2: delegate certificate expired, pending, or rejected

A delegate certificate lifts the specific numbers it covers from C to B — the answer for BYON / verified external numbers you hold certificates for. The failure modes are the certificate’s own lifecycle, and they are all silent: coverage falls to C the moment the certificate stops being active, with no call blocked and no error. Diagnostic. List the registered certificates and read the effective status column (the registry derives it live, not from what it was last told):
A certificate showing pending, expired, or revoked is one whose covered numbers have silently dropped to C — this is the most common way a previously-working call route degrades. Fix run.
  1. Re-register with a fresh chain. Obtain the renewed delegate certificate chain (PEM) from your service provider (ATIS-1000092), then re-register with the numbers listed in E.164:
  1. Match the coverage to the numbers you actually dial. Coverage falls to C per-number: a chain registered with one range or list doesn’t cover a number outside it. A registered certificate only raises the numbers it explicitly covers; E.164 the whole outbound set.
  2. Re-register before the window closes. Watch the valid until column on the dashboard section and re-register before it flips to expired — the flip is when the drop happens, not after.
Limits to plan around: an org holds at most 50 certificates (409 DELEGATE_CERT_LIMIT at the limit), re-registering the same fingerprint returns 409 DELEGATE_CERT_DUPLICATE, and a revoked certificate cannot be un-revoked — re-register a fresh chain instead. Certificate writes are admin-gated (owner/admin role); certificate reads and the posture snapshot are not.

Root cause 3: certificate chain rejected at registration

A rejected chain never enters the registry, so the numbers it was meant to cover silently attest at ownership level (C) while you believed they were covered. The registration endpoint rejects two shapes with a 422 before any coverage exists:
  • 422 INVALID_CERTIFICATEcertificate_pem held no parseable PEM-encoded certificate block (wrong encoding, truncated chain, or a non-certificate payload pasted in).
  • 422 INVALID_COVERAGE_RANGE — a covered_ranges entry had start > end.
Diagnostic. Re-issue the POST and read the response error.code directly — the two codes above name the failure exactly. A 422 at registration time means your numbers were never covered; the calls themselves carry no mark of that. Fix run. Obtain the chain again from the provider and re-submit with a well-formed PEM body and valid ranges. If your provider issued a chain that won’t parse, escalate to the provider — the registry records the authorization artifact; it does not repair the chain.

Root cause 4: per-number branded-calling override blocking RCD

This one bites from the recipient side even when attestation itself is A. RCD (branded calling) renders only on A-attested calls; a per-number branded-caller profile set on a DID can override the org-level profile for that DID, and a profile that is disabled or incomplete drops RCD for that number without touching the attestation level — the call still signs A, but the handset renders plain attestation plus CNAM, and recipients who associate the brand with the rendered name see a bare “Spam Likely”-adjacent treatment on the numbers they expected branded. Diagnostic. Check the DID’s own branded-calling surface before blaming the org default: if a per-number profile exists on the number, it overrides the org configuration for that number, and a disabled/blank profile on it removes RCD for that DID only. Fix run.
  1. Confirm attestation first. RCD is downstream of A — a downgraded number breaks RCD regardless of profile (work root cause 1/2 first).
  2. Lift the per-number profile to the org default. Unless the DID needs its own brand, remove the per-DID override and let the org-level branded calling apply. Per the Branded calling page, the org-level surface is PUT /api/v1/settings/branded-calling; a per-DID profile that was set as a one-off and left behind is the common culprit.
  3. Verify. Place a test call from the number to a carrier where your brand registration completed; confirm the brand renders instead of the bare caller ID.

Root cause 5: RCD-capable carrier coverage mismatch

RCD is carrier-dependent: the branded-calling treatment only renders on carriers where your per-carrier brand registration completed, and elsewhere the RCD payload silently drops — but the call still carries full attestation. A registration gap across the RCD-capable carrier list is therefore a downgrade of the branded treatment, not of attestation: a recipient on a non-registered carrier sees plain attestation plus CNAM while a recipient on a registered carrier sees the brand. The confusing part is that the payload is silently dropped for that call, and no error surfaces. Diagnostic. Check the per-carrier registration status on the branded- calling surface. RCD renders only where the Devotel branded-calling team has finished the registration side-band — an incomplete or not-yet-registered carrier drops the RCD while the attestation level still shows A on the call record. Fix run.
  1. Verify A-attestation first — RCD can’t ride a downgraded call (fix root cause 1/2, or the org branded-calling enabled toggle).
  2. Complete carrier registration. Registration is an operator-managed side-band with the Devotel branded-calling team, not something a tenant self-serves — until it completes on a downstream carrier, RCD stays silent there by design.
  3. Re-check after save. Remember a config save on the branded-calling surface — a changed display name, logo URL, or reason-for-call — resets the brand-verification state to unverified, so the revised brand goes back through review before it renders again.

What not to do

  • Do not chase a blocked call. A downgrade never blocks — fail-open to C is deliberate (a recoverable reporting downgrade beats a blocked call). Work the level reads, not a call-failure log.
  • Do not PUT a higher policy target and wait for calls to improve. The target is reporting intent; the softswitch signs at exactly the attested level and no more. Policy changes make the gap more visible, never smaller.
  • Do not re-register a revoked delegate certificate’s same chain. A revoked record can’t be un-revoked — obtain and re-register a fresh chain.
  • Do not treat “RCD renders nowhere” as an attestation outage. Check the branded-calling surface first: RCD is a signalling surface on top of A, not the attestation level itself.

Error-code map

No structured STIR/SHAKEN refusal exists — the call dispatches regardless — but three real codes from the compliance surface are worth recognizing when they do appear: VALIDATION_ERROR (422) on the policy/cert write endpoints means a malformed field, not a downgrade. For everything else — the C ceiling, an expired cert, a per-number override, a registration gap — there is no error: the signal lives in the posture snapshot and the branded-calling status, not the error-code catalog.

See also

  • STIR/SHAKEN attestation — what the A/B/C levels mean, where signing happens, and the controls you own.
  • Attestation posture — the policy, delegate-cert registry, and posture snapshot controls page this run uses.
  • Branded calling (Rich Call Data) — the RCD configuration surface, and why it only pays off on A-attested calls.
  • ITG traceback — the downstream obligation that comes with signed traffic, worth knowing once attestation actually attributes calls to you.
  • Error codes — every structured refusal the API returns, including the two attestation-write codes above.