> For the complete documentation index, see [llms.txt](https://docs.idlayr.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.idlayr.com/guides/high-assurance-signup.md).

# High-assurance signup

The most comprehensive IDlayr integration. Three products in sequence, each gating the next, so the verification only completes when **(a)** the user's network is supported, **(b)** their SIM hasn't recently changed, and **(c)** the device currently holds the claimed phone number.

Use it for signup, account recovery, step-up authentication on a sensitive action, or any flow where a fraudster with a freshly-swapped SIM would otherwise slip through. Each product alone closes part of the gap; all three together close the loop.

## What you'll build

A mobile app + backend integration where, from a single user gesture in your app, the backend:

1. Pre-flights with [**Eligibility**](/products/eligibility.md) to confirm the claimed number is on an MNO IDlayr supports for both SIM Swap and Secure SNA.
2. Runs [**SIM Swap**](/products/risk/sim-swap.md) to screen out lines that recently changed SIMs (a fraud-ring signature).
3. Drives [**Secure SNA**](/products/number-verification/secure-sna.md) through the IDlayr SDK on the device to prove the user's device currently holds the number.

Any gate failing → fall back to an alternative verification path — [Reverse SMS](/products/number-verification/reverse-sms.md) is the recommended fallback when Secure SNA isn't available, since it shares the same trust model (carrier-attributed) without requiring cellular data on the device. All three primary checks passing → high confidence that the right person, on the right line, with no recent SIM disruption, just completed the flow.

## Prerequisites

* An IDlayr **project** with the `eligibility`, `sim_swap`, and `secure_sna` scopes on its OAuth2 credentials. See [Projects](/enterprise-portal/projects.md).
* The project's `client_id` and `client_secret` stored as backend secrets — see [Credentials](/enterprise-portal/credentials.md).
* The relevant **mobile SDK** installed in your app — see [iOS SDK](/get-started/sdks/ios.md) or [Android SDK](/get-started/sdks/android.md).
* A **callback endpoint** on your backend if you want async terminal-state notification for the Secure SNA check (otherwise poll).
* A **fallback verification path** ready — [Reverse SMS](/products/number-verification/reverse-sms.md) is the recommended fallback (it works without cellular data and shares the carrier-attributed trust model). Eligibility, SIM Swap, or Secure SNA can each gate the flow off, and you need somewhere to send those users.

## The flow at a glance

```mermaid
sequenceDiagram
    participant App as Mobile App (with IDlayr SDK)
    participant CB as Your Backend
    participant IB as IDlayr Backend
    participant MNO as Mobile Network Operator

    App->>CB: Initiate verification (claim phone number)

    rect rgb(255,255,200)
        note over CB,IB: 1. Eligibility pre-flight
    end
    CB->>IB: GET /v1/eligibility/phone-numbers/{phone_number}

    alt Eligibility: products unavailable
        IB-->>CB: No eligible products
        CB-->>App: Fallback to alternative verification
    else Eligibility: SIM Swap + Secure SNA available
        IB-->>CB: Matched network + eligible products

        rect rgb(255,255,200)
            note over CB,IB: 2. SIM Swap risk check
        end
        CB->>IB: POST /v1/sim-swap/checks
        IB->>MNO: Query SIM-change status
        MNO-->>IB: SIM-change indicator
        IB-->>CB: no_sim_change true/false

        alt SIM Swap: change detected
            CB-->>App: Block / step up / fallback per risk policy
        else SIM Swap: clean signal
            rect rgb(255,255,200)
                note over CB,IB: 3. Secure SNA verification
            end
            CB->>IB: POST /v1/number-verification/secure-sna-checks
            IB-->>CB: check_id + verification url

            CB->>App: Hand ONLY the url to the app

            App->>App: SDK pins request to cellular interface
            App->>MNO: Follow url + redirect chain
            MNO-->>App: Response with verification code
            App->>CB: Send code to your backend
            CB->>IB: POST /v1/number-verification/secure-sna-checks/{check_id}/code with code
            IB->>MNO: Confirm verification
            MNO-->>IB: Result
            IB-->>CB: status COMPLETED, match true/false

            alt Secure SNA: match false or ERROR
                CB-->>App: Fallback to alternative verification
            else Secure SNA: match true
                CB-->>App: Verification success ✅
            end
        end
    end
```

## Step-by-step

### 0. Mint an access token (backend)

Each product call needs a Bearer token. Cache the access token until expiry; the same token works for as long as `expires_in` says.

```bash
curl -X POST https://{data_residency}.api.idlayr.com/oauth2/token \
  -u "{client_id}:{client_secret}" \
  -d "grant_type=client_credentials" \
  -d "scope=eligibility sim_swap secure_sna"
```

OAuth2 stays strictly **backend-to-backend**. The token never leaves your backend. See [Authentication](/get-started/authentication.md).

### 1. Eligibility pre-flight

Confirm IDlayr can verify this number, and that your project is approved for the carrier.

```bash
curl https://{data_residency}.api.idlayr.com/v1/eligibility/phone-numbers/+447700900000 \
  -H "Authorization: Bearer {access_token}"
```

Branch on the response:

* The list of eligible products includes **both `sim_swap` and `secure_sna`** → continue to step 2.
* Anything missing → **stop**, route to your fallback verification.

This is the cheapest gate in the flow. Skip it only if you've already pre-flighted recently for this user and cached the result. See [Eligibility](/products/eligibility.md).

### 2. SIM Swap risk check

Screen for a recent SIM change before doing the user-facing verification work.

```bash
curl -X POST https://{data_residency}.api.idlayr.com/v1/sim-swap/checks \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+447700900000"
  }'
```

SIM Swap is **synchronous** — the response carries the result immediately:

* `status: COMPLETED`, `no_sim_change: true` → clean, continue to step 3.
* `status: COMPLETED`, `no_sim_change: false` → SIM changed within the operator's reporting window. **Block, step up, or route to your fallback** per your risk policy.
* `status: ERROR` → IDlayr couldn't determine the state (MNO timeout, MNO unsupported for this line). Treat differently from `no_sim_change: false`; this is "unknown", not "fraud". Your policy decides whether to proceed or fall back.

See [SIM Swap](/products/risk/sim-swap.md) for the decision tree and error semantics.

### 3. Create the Secure SNA check (backend)

Now that Eligibility and SIM Swap have both cleared, kick off the device-side verification.

```bash
curl -X POST https://{data_residency}.api.idlayr.com/v1/number-verification/secure-sna-checks \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+447700900000",
    "callback_url": "https://your.app/callbacks/secure-sna"
  }'
```

The response includes:

* `check_id` — your handle on the check.
* `url` — the device-facing verification URL.
* `status: ACCEPTED` — the check is in flight.
* `ttl` — how long the device has to complete the verification.

**Hand only the `url` to your mobile app.** The OAuth2 access token stays on your backend; the SDK doesn't need it. The device-side redirect chain is plain HTTP and requires no `Authorization` header. See [Secure SNA](/products/number-verification/secure-sna.md).

### 4. Drive the verification from the device

Your app passes the URL to the SDK's Secure SNA method. The SDK pins the request to the cellular interface, follows the redirect chain, and returns the verification code.

**iOS:**

```swift
import IDlayrKit

let sdk = IDlayrSDK()
sdk.openWithDataCellular(
    url: URL(string: verificationURL)!,
    debug: false
) { response in
    guard let body = response["response_body"] as? [String: Any],
          let code = body["code"] as? String,
          let checkId = body["check_id"] as? String else {
        // Handle SDK error (response["error"]) — see SDK errors
        return
    }
    sendCodeToBackend(checkId: checkId, code: code)
}
```

**Android:**

```kotlin
val sdk = IDlayrSDK.getInstance()
val resp = sdk.openWithDataCellular(URL(verificationURL), false)

val body = resp.optJSONObject("response_body")
val code = body?.optString("code")
val checkId = body?.optString("check_id")
// Send code + checkId to your backend
```

If the device isn't on cellular, the SDK returns `sdk_no_data_connectivity` (or a related code) — see [SDK errors](/get-started/sdks/errors.md). Fall back from the device by reporting the failure to your backend.

### 5. Complete the check (backend)

The app sends the verification code to your backend. Your backend redeems the code for the check with POST to resolve `match`:

```bash
curl -X POST https://{data_residency}.api.idlayr.com/v1/number-verification/secure-sna-checks/{check_id}/code \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{"code" : "{code}"}'
```

Response branches:

* `status: COMPLETED`, `match: true` → ✅ verification success. Proceed with signup / authentication / sensitive action.
* `status: COMPLETED`, `match: false` → the device's network-attached number didn't match the claimed number. Route to fallback.
* `status: ERROR` or `EXPIRED` → see [Secure SNA error codes](/products/number-verification/secure-sna/error-codes.md). Route to fallback.

The `match: true` outcome means all three products agreed: eligible carrier, clean SIM state, device holds the number. That's the high-assurance signal.

### 6. Receive the terminal-state callback (optional)

If you supplied a `callback_url` in step 3, IDlayr POSTs the terminal-state SecureSNACheck to it once the check resolves. The callback is signed via JWKS — **verify the signature** before trusting the payload. See [Signed HTTP messages](/get-started/signed-http-messages.md).

For most production integrations, **both the POST to redeem the verification code response (step 5) and the callback** will deliver. Pick one as your authoritative signal (the callback is recommended for distributed systems) and treat the other as a backup. Deduplicate by `check_id`.

## Decision policy: which gate failure means what

| Stage       | Failure mode                                                        | Recommended action                                                                                                          |
| ----------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Eligibility | No products available, or `sim_swap` / `secure_sna` not in the list | Skip the IDlayr flow entirely. Route to your fallback verification.                                                         |
| Eligibility | `not_found`, `internal_server_error`, transient errors              | Retry once; on persistent failure, treat as no-eligibility and fall back.                                                   |
| SIM Swap    | `no_sim_change: false`                                              | Block, step up, or fallback per your risk policy. **Not** the same as `ERROR`.                                              |
| SIM Swap    | `status: ERROR` (MNO timeout, unsupported)                          | "Unknown" state. Decide per policy: proceed cautiously, or fall back.                                                       |
| Secure SNA  | `match: false`                                                      | Claimed number doesn't match the device's network-attached number. Fall back.                                               |
| Secure SNA  | `EXPIRED`                                                           | Device didn't complete the verification in time. Most commonly Wi-Fi-only or unstable cellular. Retry once, then fall back. |
| Secure SNA  | `ERROR`                                                             | Carrier-side failure. See [error codes](/products/number-verification/secure-sna/error-codes.md). Fall back.                |
| SDK         | `sdk_no_data_connectivity` etc.                                     | Device-level — surface "no mobile connection" to the user and route to fallback.                                            |

## Common pitfalls

* **Don't conflate "couldn't determine" with "fraud signal".** A SIM Swap `ERROR` isn't a SIM change; a Secure SNA `EXPIRED` isn't a failed match. Your fallback path should distinguish.
* **Don't pass the access token to the device.** The SDK never needs it. Hand only the verification URL. See [Authentication](/get-started/authentication.md).
* **Don't skip Eligibility on every request.** It's the cheapest gate; running it first saves you SIM Swap and Secure SNA spend on numbers that were never going to work.
* **Don't retry on 4xx.** A 400/404 indicates a contract error — your retry will fail the same way. Retry with exponential backoff only on 5xx.
* **Verify callback signatures.** A device-side success is not authoritative until the signed backend callback (or the POST redemption of the verification code on your backend) confirms it.
* **Cache the access token.** Don't mint a fresh one per request — you'll hit rate limits on the token endpoint long before you do on the product endpoints.

## Sandbox testing

You can exercise the entire flow end-to-end against the sandbox without real carrier traffic. The MSISDN suffix you submit drives the simulated outcome at each gate. See [Sandbox testing](/get-started/sandbox-testing.md) for the per-product suffix maps; you can hand-pick suffixes that produce each branch of the decision tree above.

## Reference

* [Eligibility](/products/eligibility.md), [SIM Swap](/products/risk/sim-swap.md), [Secure SNA](/products/number-verification/secure-sna.md)
* [iOS SDK](/get-started/sdks/ios.md), [Android SDK](/get-started/sdks/android.md), [SDK errors](/get-started/sdks/errors.md)
* [Authentication](/get-started/authentication.md), [Signed HTTP messages](/get-started/signed-http-messages.md), [Sandbox testing](/get-started/sandbox-testing.md)
* API Reference for the request and response schemas — [docs.idlayr.com/api-reference](https://docs.idlayr.com/api-reference)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.idlayr.com/guides/high-assurance-signup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
