Identity risk gate: fused signals — port-event recency, SIM swap, and Silent Auth
POST /api/v1/numbers/network-apis/identity:gate answers one question for your registration or login funnel: should this phone-number–anchored transaction proceed, step up, or stop? It fuses operator-asserted network signals and signals you already hold into a single composite risk score, then resolves one of three decisions — allow, review, or deny — against your thresholds. The Verify fraud gate applies the same kind of fusion inside an OTP send, bound to a Verify profile; the identity gate is the same idea exposed as a general endpoint you can call at any funnel moment — registration, login, checkout, payout — before you commit to anything more expensive.
Everything the gate does is a tenant-owned control (see the compliance posture): the fuse-and-decide kernel runs only when you call it, your per-request thresholds decide what the score means, and your funnel decides what a review becomes. The gate itself sends nothing — every signal is a silent, read-only assertion, so calling it never initiates an outbound SMS or call.
1. What the gate scores, and when it fires
The gate scores one phone number in one transaction context. You call it with the number plus whichever caller-held signals you already have, and it runs two parallel collections:- Operator dips (automatic). When a CAMARA Open Gateway operator is configured for your account, the gate concurrently queries SIM-swap recency, number-recycling tenure, device reachability, device-location verification (when you pass a claimed area), Silent-Auth possession (when you pass a device-bound access token), and the operator’s own call-forwarding assertion.
- Caller-held signals. Signals the operator dip does not own and you already hold — most importantly cross-carrier port-event recency (
portedRecently), plus roaming state, a number-reputation bucket, and any unconditional call-forwarding state you read from a Lookup data package.
deny threshold returns deny; at or above the review threshold returns review; below both returns allow. The response also carries review_or_block — a single boolean (decision !== "allow") your funnel can test directly to route a user into its step-up path.
Every dip is fail-soft: an operator that is unreachable, unconfigured, or slow lowers the number of signals the verdict rests on but never fabricates risk, and never absolves it either. A signal that could not be determined adds zero points and is named in signals_unavailable so your logs show exactly what the verdict was based on.
Where it fires in a funnel
- Registration: call before account creation completes — a recent port plus a recent SIM swap on a brand-new account is the classic account-takeover replay.
- Login on a new device: call with the Silent-Auth access token bound to the device; a possession mismatch plus any corroborating signal should step up, not proceed.
- Checkout / payout: call before authorizing the transaction; use
review_or_blockas the trigger for your existing step-up (an OTP on a stronger factor, a voice-print challenge, manual review).
2. The fused signals
The kernel consumes a fixed set of tri-state signals. Only an asserted negative adds risk — a clean assertion and an unknown one both add nothing.
Two properties of this set matter for how you reason about a verdict:
- Signals are independently fused, not shadowed. A caller-held
callForwardingUnconditionaland the operator-asserted forwarding dip can both fire on the same transaction and add up as corroborating evidence rather than double-counted noise. - A lone signal resolves; it never hard-fails. No single signal — not even a possession mismatch — mechanically blocks a transaction. A lone moderate signal lands at
reviewunder the default weights, which is the knob you use to require corroboration before anything is refused. Blocking is your threshold’s decision, applied to the composite.
3. Kernel weighting: the additive model
The score is the sum of observed negative assertions, capped at 100, mapped by your thresholds. Default weights and thresholds:
Default thresholds: review at 35, deny at 70.
Why the weights sit where they do:
- Port-event recency defaults to 35 — above number recycling (30), below SIM swap (45). A port moves the number onto a new network entirely, which is a stronger takeover vector than a same-carrier reassignment but corroborates rather than confirms. At exactly the review threshold, a lone
ported_recentlyassertion lands the transaction inreview— never auto-deny. It denies only when fused: port (35) + SIM swap (45) = 80, port + possession mismatch = 80, port + operator-asserted forwarding = 80. - Operator-asserted evidence outweighs caller-held claims of the same fact (45 vs 35 for forwarding) — the carrier’s own assertion is harder to spoof than one your side holds.
- The 70 deny threshold is reachable by any pair of strong signals (45 + 45, 45 + 40, 45 + 35 = 80) but unreachable by weak corroboration alone — three weak signals (15 + 20 + 20 = 55) still only review. Deliberate: weak signals step a transaction up; they do not kill it.
- Why nothing hard-fails. The kernel is additive and fail-open on missing data, so there is no “one signal equals block” carve-out. A hard block is always your
denythreshold doing its job on a composite — which keeps a single noisy dip from refusing legitimate users, and puts the refusal criterion on the record inreasonsevery time.
portedRecently below 35 when your funnel already screens ports upstream, or raise the review threshold when a step-up is cheap for your users.
4. Configuring your posture
Per Orbit’s compliance model, the posture is yours: the gate ships no platform-side hard gate, and every knob is per-request. Two objects tune it:weights— per-signal point overrides (0–100 each), merged onto the defaults; omitted keys keep their defaults.thresholds—reviewanddenyscore cutoffs (0–100), merged onto 35/70.
review_or_block: true is the branch point — route it into your own step-up (a Verify OTP with channel escalation, a voice-biometric challenge, or a manual-review queue) rather than treating review as a block. In the Verify stack, the profile’s riskStepUpThreshold / riskBlockThreshold play the same role as this endpoint’s thresholds; keep one posture across both by setting them from the same risk appetite rather than tuning each surface in isolation.
The look-back windows are yours too: simSwapMaxAge (1–2400 hours, default 240) and numberRecyclingMaxAge (1–2555 days, default 30) decide what “recent” means for the operator dips. When you know the exact port-in completion timestamp for a number you just provisioned, tighten the recycling window to everything since the port and assert numberRecycled: false — the verdict then records that recycling was evaluated-and-clean instead of unavailable.
5. A worked call, and troubleshooting false positives
A registration-time gate call with a caller-held port signal and a SIM-swap dip returning:risk_level bands the score (unknown means no signal was evaluable — treat that as “no data”, never as “trusted”).
Common false-positive shapes and their resolution:
- Legitimate user ports in, then registers. Bring your own port-in timestamp and pass
portedRecently: falsewhen your inventory says the port is older than your recency window — the flag is caller-held precisely so your ledger resolves it. Where the port is real and recent and the user is legitimate, the intended outcome isreview, notdeny— a 35-point lone signal lands there exactly so your step-up (not a refusal) handles it. - Forwarding set for a legitimate reason.
call_forwarding_unconditionalat 35 also lands a lone line inreviewrather than deny, for the same reason — forwarding has legitimate uses, so corroboration decides. - A
denywithout clear cause. Readreasons— every point is explained there — andsignals_unavailablefor what never evaluated. Then move the specific weight or the deny threshold in your next request rather than blanket-disabling the gate. - Operator unreachable at decision time. The missing dips appear in
signals_unavailableand the verdict degrades to the caller-held half of the fusion — which is whyreview_or_blocknever treats absent data as risk. If your funnel requires operator evidence to proceed, gate onrisk_level === "unknown"explicitly.
See also
- The Verify fraud gate: score, verdict, and the fallback-constrained chain — the OTP-send-bound sibling of this endpoint and the per-profile thresholds that mirror
thresholds. - Composite pre-send risk verdict — how
verify_signalandvoice_biometrics_signalfold across detectors onPOST /risk/score. - Number portability model — the port lifecycle the caller-held port-event signal reads from.
- Reassigned numbers database — the roster screen behind number-recycling tenure checks on your own sends.
- Network APIs reference — the endpoint contract, including
identity:gateandrisk:score. - Verify fraud gate — the console surface for the Verify-side gate configuration.