Before you start
- API in TEST:
https://test-api.segmnt.cloud - Everything on this page uses the session cookie (
segmnt_session), not an API key. - The number must be a Saudi or GCC mobile. Send a full international number
(
+CC...), or a local number together withcountry(see the table below). Withoutcountry, a local number is treated as Saudi. Spaces, dashes, brackets and dots are allowed. The number is stored in the form+CC...(E.164), for example+966512345678. - SMS is not live yet. See Not live yet.
country is one of sa, ae, kw, qa,
bh, om:
A leading
0 (trunk) in a local number is dropped.
1. Check whether the phone step is required
GET /v1/me returns two fields on account:
In this version
phoneVerificationRequired is always false, so nothing is
gated. When the phone step ships and the gate is switched on, use this field to
show the step. Do not block the whole app on it: then only the first upload
is blocked.
2. Start the code
country:
202):
phonein the answer is masked. Keep the full number only if you need it; we never return it.- The code is 6 digits and expires in 10 minutes (
expiresAt). - At most 5 codes per account per hour. More gets
429 phone_rate_limited. - Each challenge is for one phone number. Starting again makes a new challenge; the old one still works until it is used or it expires.
- A banned account or phone number gets
403 banned. - A number that is not a Saudi or GCC mobile gets
400 invalid_phone. - A
countrythat is not one ofsa,ae,kw,qa,bh,omgets400 invalid_country. - If the SMS provider cannot send the code, you get
502 sms_send_failed. Nothing is stored, so try again.
3. Verify the code
Send thechallengeId, the 6-digit code, and a fingerprint.
200):
fingerprint:
- It is a stable identifier for the device or browser (for example a random id you store in the browser, or a device hash). 1 to 256 characters.
- It is stored only as a salted hash, linked to the account. The raw value is never kept.
- A blocked account, phone number or device gets
403 banned.
- One use. A challenge verifies one phone number once.
- 10-minute expiry. After that, you get
410 code_expired; start again. - 5 wrong codes close it. After 5
invalid_codeanswers, later codes get429 too_many_attempts; start a new code. - Safe to retry. Repeating a successful call with the same
challengeIdreturns200again and does not verify twice.
4. Upload is not blocked in this version
In this version an upload is not blocked for phone verification. When your app (or the dashboard) starts an upload withPOST /v1/projects/{projectId}/uploads, the ban check still runs:
403 phone_verification_required is not returned in this version. When the
phone step ships and the gate is switched on, a new free account that has not
verified gets it, and you finish step 3 first. Paid plans
and accounts that existed before the feature are not gated. The ban check
applies to every plan.
When the gate is switched on, it is active only if an SMS provider is
configured. While SMS is not live (see Not live yet), the phone
gate stays off; the ban check still applies.
Not live yet
- SMS sending. Sending a real SMS costs money, so no SMS provider is enabled
until a provider is approved and its monthly cost is agreed. Until then
POST /v1/me/phone/startanswers503 sms_not_configured. When a provider is approved, the same calls work with no change from you. - The dashboard phone step. Until it ships, the API is the source of truth:
read
phoneVerificationRequiredfromGET /v1/meand call the two endpoints yourself. - A device list. You cannot list the devices of an account yet.
testCode in the start answer so our automated tests can finish
the flow without a real SMS. testCode is never present in production.
Errors
Errors useapplication/problem+json. Use the code field in your code, not
the text. The type field links to https://docs.segmnt.cloud/errors/{code}.
Tested in TEST
Checked againsthttps://test-api.segmnt.cloud on 14 Oct 2026, after the
phone-verification release reached TEST:
POST /v1/me/phone/startwith no session →401 unauthorized.POST /v1/me/phone/verifywith no session →401 unauthorized.GET /v1/me/phone/start→405 method_not_allowed(both routes arePOST).
api/src/phone.test.ts: Saudi and
GCC E.164 normalization, an unknown country (400 invalid_country), start and
verify, the rate limit, the 10-minute expiry, the 5 wrong codes, the idempotent
retry, the upload gate, the ban checks, and a failed SMS send (502 sms_send_failed, with nothing stored). The signed-in path needs a real session,
so it is not re-run by hand here.