MX Labs Open Gateway
MX Labs Open Gateway

Verify a phone number without sending an SMS.

Carrier-grade phone verification across mobile operator networks. Silent-first, with an SMS one-time code as the automatic backstop when a silent check cannot run.

Try the sandbox
One integrationone API key, one integration
Carrier-gradethe operator network confirms the number, no SMS guesswork
Silent-firstverifies in the background, no OTP to type; SMS is only a fallback
Live in an afternoonSDKs, sandbox, drop-in code
Live on Singtel, M1 & Taiwan Mobile — more operators rolling out Network-level (CAMARA) verification MIT-licensed open-source SDKs (Node & Python)

See what your user experiences

Pick a scenario. It runs against the live API in sandbox mode - nothing reaches a real operator or sends a real SMS.

Sign in
Your app, using MX Labs Open Gateway
Mobile number
+60 12-345 6789
Pick a scenario above to see the sign-in flow.
Show the technical details (the API calls behind it)
-

Install

Node
npm install mxlabs-number-verify
Python
pip install mxlabs-number-verify

Basic usage

The SDK manages the session and polling. You open the auth URL on the user device; that request over the cellular network is what proves the number.

import { MXNumberVerify } from 'mxlabs-number-verify';

const nv = new MXNumberVerify({ apiKey: process.env.MXLABS_API_KEY });

const result = await nv.verifyNumber('+60123456789', {
  onAuthUrl: url => redirectUserToUrl(url)   // device opens it over cellular
});

if (result.status === 'verified') grantAccess(result.phone);
else await nv.smsSend(result.sessionId);      // backstop: one-time code by SMS

Python is identical: nv.verify_number(...).

Advanced: manage the session yourself

Drive the session, redirect and fallback yourself:

const { sessionId, authUrl } = await nv.start('+60123456789');
// device opens authUrl over cellular, then:
const result = await nv.pollVerify(sessionId);
if (result.status !== 'verified') {
  const { masked } = await nv.smsSend(sessionId);
  await nv.smsVerify(sessionId, codeFromUser);
}

Response values

verify() runs one check and returns a status. Poll until you get a terminal status (the SDK does this for you).

statusMeaningWhat to do
pending The silent check is still running, waiting on the operator. Not final. Keep polling verify() until a terminal status (or timeout).
verified The number is confirmed. method shows how (number_verification or sms_otp); phone echoes it back. Grant access.
not_verified The operator checked and the number is not active on this device. Do not grant access. Offer the SMS fallback (fallback: sms_otp).
nv_unavailable The silent check could not run (e.g. Wi-Fi, timeout, or sandbox). Not the number's fault. reason says why. Fall back to an SMS one-time code (fallback: sms_otp).

Other responses

started start() succeeded. Returns session_id and auth_url (open on the user's device over cellular).
sms_sent sms_send() dispatched the code. Returns masked (masked number) and expires_in (seconds).
invalid / expired sms_verify() — the code was wrong (invalid) or has expired (expired). Ask the user to retry or resend.
ok ping() — the API and your key are healthy.
error A request-level failure. error is one of invalid_api_key, invalid_phone, rate_limited (with retry_after), session_not_found_or_expired, missing_session_id, unknown_action.

For developers

Try it against the sandbox in five minutes, no signup. Sandbox calls never reach a real operator or send a real SMS.

Sandbox API key
sbx_demo_9f3b7c1e0a2d4856b1c9e7f2a6d40b83
Test numbers
+10000000001Silent success → verified
+10000000002Silent unavailable → SMS backstop (code 000000)
+10000000003Wrong number → not verified
SDK (Python; Node is identical)
pip install mxlabs-number-verify

from mxlabs_number_verify import MXNumberVerify
nv = MXNumberVerify(api_key="sbx_demo_9f3b7c1e0a2d4856b1c9e7f2a6d40b83")
print(nv.verify_number("+10000000001"))   # {'status': 'verified', ...}
Or raw HTTP
curl -s https://api.mxlab.sg/sdk.php \
  -H "X-API-Key: sbx_demo_9f3b7c1e0a2d4856b1c9e7f2a6d40b83" \
  -d action=start -d phone=+10000000001

Full API reference: Node / Python READMEs. Machine-readable contract: OpenAPI spec.

Sandbox and live keys — one key works across every operator network.