Skip to content

Mobile numbers

Mobile numbers are real SIM cards in Android phones. A phone running the SIM Bridge app forwards the SMS it receives to clearance.rest, so those messages resolve GET /sms/wait like any other number. Use them for services that reject virtual numbers.

Getting a number onto your project takes two independent steps:

  1. Verify the number, done by whoever holds the phone. In the app, the number is verified with a code sent to it.
  2. Attach it to your project, done by scanning your QR code in the app.

You cannot choose which number gets attached. The person holding the phone decides, and you cannot name a number you cannot see.

  1. Install the SIM Bridge app on the phone.

    Open this link in the phone’s browser. It needs no API key:

    https://api.clearance.rest/numbers/providers/mobile/download_apk

    Only the latest release is served.

  2. Create a claim ticket on your backend.

    curl -X POST https://api.clearance.rest/numbers/providers/mobile/claim/ticket \
    -H "X-API-Key: $CLEARANCE_REST_API_KEY" \
    -H "content-type: application/json" \
    -d '{ "label": "agency-1" }'
    { "success": true, "ticket": "cst_3f9a…", "expires_at": 1700000060000, "ttl_ms": 60000 }

    The ticket is single-use and valid for 60 seconds. It exists because a browser WebSocket cannot send headers and your API key must never reach the browser. The optional label is your own note, kept on every QR the session produces.

  3. Open the claim socket in the browser.

    Give the browser only the ticketed URL. The socket shows a QR code, keeps it fresh, and tells you when it is scanned.

    const socket = new WebSocket(
    `wss://api.clearance.rest/numbers/providers/mobile/claim/socket?ticket=${ticket}`,
    );
    socket.onmessage = ({ data }) => {
    const event = JSON.parse(data);
    switch (event.type) {
    case 'qr': renderQr(event.qr_payload); break; // called again on every rotation
    case 'scanned': showScanned(event.phone_number); break;
    case 'assigned': showDone(event); break;
    case 'error': showError(event.message); break;
    }
    };
  4. Scan the QR in the app.

    The person with the phone scans the QR in the SIM Bridge app. The number is attached and appears in GET /numbers/list with provider: "mobile".

Each message is a JSON text frame with a type:

type When Fields
session Once, on connect. session_id, ttl_ms
qr On connect, and every time the QR rotates. token, qr_payload, issued_at, expires_at
scanned The current QR was scanned. at, number_id, phone_number, carrier_name
assigned Right after scanned, once the number is attached. at, unchanged, and the number’s fields
error Right after scanned, if attaching failed. code, message

Render qr_payload as a QR code. The QR rotates before it expires, and each qr event replaces the last.

After assigned, the server stops rotating and closes the socket with code 1000. To attach another number, get a new ticket and connect again. If you close the socket without an assignment, the QR in flight stops working immediately.

The socket answers a ping text frame with pong, if you want a liveness check.

POST /numbers/providers/mobile/claim/rest returns a single token and its qr_payload in one call. The token is single-use and expires after 30 seconds, which is too short for a person to act on by hand, so prefer the socket for real use. It is handy for a quick check: add ?preview=true to get the QR as an SVG image.

curl -X POST "https://api.clearance.rest/numbers/providers/mobile/claim/rest?preview=true" \
-H "X-API-Key: $CLEARANCE_REST_API_KEY" -o claim-qr.svg

Mobile numbers add two states that depend on the phone:

  • OFFLINE: no signal from the phone for 30 minutes or more. It does not block delivery, since an incoming SMS is itself a sign the phone is alive.
  • SIM_REMOVED: the SIM is not in the phone. SMS are not delivered to waiters.

A number can be attached to only one project at a time. If it is attached to another project, yours shows it as MOVED. See Managing numbers.

A leaked token could let someone attach a number you did not intend. That is clutter rather than a leak: you see the number and can remove it with POST /numbers/release, which for a mobile number only removes your project’s attachment.