> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Network signals before you send: GSMA Open Gateway and CAMARA APIs

> Wire operator-asserted identity and fraud signals — SIM-swap, silent auth, roaming, KYC-match, risk score, and QoD — into your send, login, and onboarding flows without OTPs or carrier PII exposure.

# Network signals before you send

A message costs money to send. A message delivered to a SIM that was swapped yesterday, sent to a handset that just moved countries, or accepted by a number whose registered owner no longer matches your customer costs more — in account takeovers, in compliance exposure, and in spend you cannot recover.

<Note>
  This guide covers the **operator-asserted** signals (SIM-swap, Scam Signal, QoD, and friends). The **cross-tenant SMS-pumping reputation feed** — a different "network signals" surface — is documented on the [shared fraud-reputation concept page](/concepts/network-signals-fraud-reputation).
</Note>

Orbit's Network APIs give you the operator's own answer to "is this number still the customer I think it is?" before you commit anything. These are **silent, no-OTP signals**: the mobile network asserts facts about a subscriber without sending the subscriber a message, and without exposing the carrier's underlying PII. You get a verdict — swapped or not, verified or not, matched or not — never the carrier's record.

This guide walks the canonical task shapes: gating an outbound campaign, scoring a login, replacing an SMS OTP on a known device, matching KYC attributes at onboarding, checking operator coverage before you lean on it, and deciding when Quality-on-Demand is worth a session. Per-endpoint schemas are in the [Network APIs reference](/api-reference/network-apis) and are not repeated here.

<Note>
  These signals are **advisory inputs to your own controls**, never a replacement for them. Tenants own their consent, KYC, and compliance posture; Orbit is the conduit that gets the operator's verdict to your decision point. See [Consent management](/compliance/consent-management) and [Country compliance requirements](/compliance/country-requirements).
</Note>

## Inventory: one line per signal

All endpoints live under `/api/v1/numbers/network-apis`. Phone numbers are E.164; every request carries your `X-API-Key`.

| Signal                            | Endpoint                               | When to call it                                                                                                                                                                      |
| --------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Operator status                   | `GET /status`                          | Before anything else — is a GSMA/CAMARA operator configured for this deployment at all?                                                                                              |
| Number Verification (Silent Auth) | `POST /number-verification:verify`     | Confirm a device holds the number it claims, without sending an OTP. The silent replacement for SMS one-time codes.                                                                  |
| SIM Swap — check                  | `POST /sim-swap:check`                 | Before you trust a number: was the SIM swapped within your look-back window? A recent swap is a strong account-takeover signal.                                                      |
| SIM Swap — retrieve date          | `POST /sim-swap:retrieve-date`         | When you want the raw timestamp of the last SIM change rather than a boolean for your own window logic.                                                                              |
| SIM Swap — subscriptions          | `POST /sim-swap/subscriptions`         | Continuous monitoring of a high-value number instead of polling the check endpoint.                                                                                                  |
| Device Swap                       | `POST /device-swap:check`              | Same question, different layer: did the SIM move to a different handset (IMEI change)? Corroborates takeover when SIM Swap is clean.                                                 |
| Device Roaming Status             | `POST /device-roaming-status:retrieve` | Before you send to a number whose subscriber should be home-network — a SIM suddenly answering abroad corroborates fraud.                                                            |
| KYC Match                         | `POST /kyc-match:match`                | At onboarding: match the attributes the user typed (name, birthdate, document) against the operator's record. Per-attribute verdicts — the underlying PII never leaves the operator. |
| Device Location Verification      | `POST /device-location:verify`         | Confirm the device is inside a claimed geofence without learning its coordinates.                                                                                                    |
| Device Status reachability        | `POST /device-status:reachability`     | Is the device even connected to the network? `NOT_CONNECTED` on a supposedly active account corroborates fraud.                                                                      |
| Carrier Billing                   | `POST /carrier-billing:charge`         | Charge a one-time payment to the subscriber's operator bill (Direct Carrier Billing), server-capped per transaction.                                                                 |
| Age Verification                  | `POST /age-verification:verify`        | At age-gated checkout: operator-asserted "at least N years old" verdict. Returns a boolean, never a birthdate.                                                                       |
| Scam Signal                       | `POST /scam-signal:assess`             | During a live transaction at a bank/fintech: anonymised anti-APP-fraud signals (active call, call forwarding, SIM swap) plus a coarse risk level.                                    |
| Identity Risk Score               | `POST /risk:score`                     | One fused verdict at login, signup, checkout, or payout — every operator signal plus any caller-held signals you already have.                                                       |
| Quality-on-Demand                 | `POST /qod-sessions`                   | When you need a low-latency or high-throughput data bearer for a device on demand (e.g. emergency voice, field telehealth).                                                          |

## Task walkthroughs

### Gate an outbound campaign on SIM-swap and roaming

The cheapest place to catch a bad number is the campaign orchestration code that already validates recipients. Screen before you send — not after the delivery receipt arrives.

<Steps>
  <Step title="Check for a recent SIM swap">
    ```bash theme={null}
    curl -X POST "https://api.orbit.devotel.io/api/v1/numbers/network-apis/sim-swap:check" \
      -H "X-API-Key: $ORBIT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "phoneNumber": "+14155550100", "maxAge": 240 }'
    ```

    `swapped: true` means the SIM changed within the last 240 hours. For a high-value re-engagement campaign, that recipient moves to your review queue.
  </Step>

  <Step title="Check roaming on recipients who should be home">
    ```bash theme={null}
    curl -X POST "https://api.orbit.devotel.io/api/v1/numbers/network-apis/device-roaming-status:retrieve" \
      -H "X-API-Key: $ORBIT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "phoneNumber": "+14155550100" }'
    ```

    A `roaming: true` on a domestic-only customer base corroborates the swap signal; either one alone rarely decides.
  </Step>

  <Step title="Apply your own policy">
    Your campaign code applies the verdicts to your thresholds. **Score-affected recipients** get held or refused; the screen itself never sends, routes, or blocks anything — outbound exits only through the normal send path.

    ```typescript theme={null}
    async function screenRecipient(phoneNumber: string): Promise<"send" | "review"> {
      const [swap, roaming] = await Promise.all([
        fetch(`${API}/api/v1/numbers/network-apis/sim-swap:check`, {
          method: "POST",
          headers: { "X-API-Key": process.env.ORBIT_API_KEY!, "Content-Type": "application/json" },
          body: JSON.stringify({ phoneNumber, maxAge: 240 }),
        }).then((r) => r.json()),
        fetch(`${API}/api/v1/numbers/network-apis/device-roaming-status:retrieve`, {
          method: "POST",
          headers: { "X-API-Key": process.env.ORBIT_API_KEY!, "Content-Type": "application/json" },
          body: JSON.stringify({ phoneNumber }),
        }).then((r) => r.json()),
      ]);

      if (swap.data.swapped) return "review";
      if (roaming.data.roaming) return "review";
      return "send";
    }
    ```
  </Step>
</Steps>

For high-volume campaigns, cache verdicts per recipient for the campaign window — a SIM-swap answer does not change meaningfully inside a send cycle.

### Fuse risk:score into a login or checkout flow

Every signal above answers one narrow question. `risk:score` answers the whole one: given everything the operator can assert plus everything you already hold, is this interaction safe? Call it at the moments that create liability — login, signup, checkout, payout — not just at OTP send.

```typescript theme={null}
async function scoreLogin(phoneNumber: string, session: { roaming?: boolean; reputation?: string }) {
  const res = await fetch(`${API}/api/v1/numbers/network-apis/risk:score`, {
    method: "POST",
    headers: { "X-API-Key": process.env.ORBIT_API_KEY!, "Content-Type": "application/json" },
    body: JSON.stringify({
      phoneNumber,
      context: { action: "login", reference: session.id },
      // Pass signals you already hold — the operator dip is independent of them.
      roaming: session.roaming,
      reputationRiskLevel: session.reputation,
    }),
  });
  const { data } = await res.json();
  // data.decision: "allow" | "review" | "deny"
  // data.risk_score: 0-100   data.reasons: machine-readable reason codes
  // data.signals_unavailable: which legs could not be answered (fail-soft)
  return data;
}
```

Wire the verdict to your session policy: `allow` proceeds, `review` triggers your own step-up (an existing factor, a manual queue), `deny` refuses the session. Unavailable signals are listed in `signals_unavailable` and contribute nothing — a partial verdict never reads as a clean one, and the request never fails because one leg was unconfigured. Tune `weights` and `thresholds` per request when one surface (checkout) needs a stricter posture than another (login).

### Replace an SMS OTP with Silent Auth on a known device

An SMS OTP costs a message, leaks through SS7-class interception, and asks the user to transcribe a code. Number Verification (Silent Auth) asks the operator instead: the device's data connection itself proves it holds the number. Use it for the known-customer step-ups where you currently send an OTP; keep SMS OTP as the fallback for devices where the network assertion is unavailable (Wi-Fi-only contexts, unconfigured operators).

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/numbers/network-apis/number-verification:verify" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phoneNumber": "+14155550100", "accessToken": "device_bound_token_from_ciba_flow" }'
```

`devicePhoneNumberVerified: true` is the operator's confirmation; anything that is not an explicit network-verified match reads `false` — the check fails closed. Fall back to your normal OTP path on `false`. The full Verify lifecycle for the fallback route is in the [verification lifecycle concept](/concepts/verification-lifecycle) and the [Verify fallback chains guide](/guides/verify-fallback-chains).

### KYC-match users at onboarding

KYC Match compares the identity attributes a user types into your onboarding form against the operator's subscriber record and returns a per-attribute verdict — `"true"`, `"false"`, or `"not_available"` for each attribute you submitted. The operator's underlying PII is never returned and never stored on your side.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/numbers/network-apis/kyc-match:match" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+14155550100",
    "name": "Priya Sharma",
    "birthdate": "1991-03-14"
  }'
```

A `nameMatch: "false"` on an onboarding that claims the number's owner is the applicant is a strong signal to step up — request a document in your own flow. Your consent basis for consulting the operator's record is tenant-owned: pair this with your existing KYC disclosure and consent capture (see [Consent management](/compliance/consent-management)).

### Inspect operator status before leaning on coverage

Every Network API fails closed when no GSMA/CAMARA operator is configured: `503 SERVICE_UNAVAILABLE`, never a fabricated identity result. Probe the surface at integration time and on a schedule:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/numbers/network-apis/status" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

`{ "enabled": false }` means route around the surface: fall back to OTP for silent-auth steps, to your own heuristics for risk, and queue KYC-match steps for manual review. An `enabled: true` is deployment-level, not per-country — individual subscriber lookups still depend on whether the subscriber's operator participates in the signal you asked for. Treat `signals_unavailable` on `risk:score` as the per-request view of the same boundary.

### When QoD matters

Quality-on-Demand allocates a programmable QoS bearer for a device's data path — latency-bound applications are the canonical user. If you run emergency voice, field telehealth, or any session where a congested cell ruins the call, a QoD session asks the operator for a prioritized bearer for the duration of that session.

```bash theme={null}
# Create a low-latency bearer for the device toward your media server
curl -X POST "https://api.orbit.devotel.io/api/v1/numbers/network-apis/qod-sessions" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+14155550100",
    "applicationServerIpv4": "203.0.113.10",
    "qosProfile": "QOS_E",
    "duration": 3600
  }'

# Extend a live session when the call runs long
curl -X POST "https://api.orbit.devotel.io/api/v1/numbers/network-apis/qod-sessions/qod_abc123/extend" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "requestedAdditionalDuration": 1800 }'

# Tear it down when the session ends
curl -X DELETE "https://api.orbit.devotel.io/api/v1/numbers/network-apis/qod-sessions/qod_abc123" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

QoD shapes a **data** bearer only — it prioritizes the device's packet path to your application server. Voice routing itself is unchanged. Skip QoD when latency does not gate your outcome: bulk messaging, batch analytics, and store-and-forward flows gain nothing from a prioritized bearer.

## Coverage and fail-soft behavior

Two questions decide how much of this surface serves a given number:

1. **Is a GSMA/CAMARA operator configured for the deployment at all?** `GET /status` answers this. On `false`, every endpoint returns `503` and your integration must route around the whole surface.
2. **Does the subscriber's operator answer this specific signal?** Within an enabled deployment, coverage varies per operator and per signal. `risk:score` surfaces this per request in `signals_unavailable`; the individual endpoints fail closed (SIM Swap `swapped: false` is only meaningful against a `200` — a `503` or `422` means "no answer", not "no swap").

Build fail-soft on top of that: absent a signal, fall back to what you had before — SMS OTP instead of Silent Auth, your own velocity heuristics instead of `risk:score`, manual review instead of KYC-match. Never treat `SERVICE_UNAVAILABLE` as a clean result.

## Tenant-raised controls

<Warning>
  These operator signals **complement, never replace, your own consent and KYC posture**. Orbit surfaces the network's verdict to your decision point; it does not own your regulatory obligations. Consent capture, KYC program design, age-gating policy, and fraud thresholds are tenant-owned controls — Orbit is the conduit. Whatever the signal says, the act decision (allow, review, refuse) and its regulatory basis are yours.
</Warning>

Concretely:

* **Consent.** Consulting the operator's record about a subscriber is a processing act your privacy notice and consent capture must cover. Pair Silent Auth, KYC Match, and risk scoring with your existing consent flows.
* **KYC programs.** KYC Match returns per-attribute verdicts; whether a `"false"` verdict refuses onboarding, steps up to document review, or merely informs an agent is your program's call.
* **Advisory scoring.** `risk:score` and Scam Signal never touch a message, session, or charge. The `decision` field is a suggested action against thresholds you can override per request — your own policy applies the verdict.

## What's next

* [Network APIs reference](/api-reference/network-apis) — every endpoint's parameters, response schema, and error contract.
* [Verification lifecycle concept](/concepts/verification-lifecycle) — how OTP sessions behave when you fall back from silent signals.
* [Verify fallback chains guide](/guides/verify-fallback-chains) — ordered channel chains when Silent Auth is one leg of a broader verification posture.
* [SMS-pumping protection guide](/guides/sms-pumping-protection) — the complementary fraud screen for the spend side of the send.
* [Consent management](/compliance/consent-management) and [Country compliance requirements](/compliance/country-requirements) — the tenant-owned controls these signals feed into.
