curl --request GET \
--url https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": {
"phoneNumber": "<string>",
"valid": true,
"callingCountryCode": "<string>",
"nationalFormat": "<string>",
"carrier": {
"name": "<string>",
"type": "<string>",
"mcc": "<string>",
"mnc": "<string>"
},
"portability": {
"ported": true,
"portedDate": "2023-11-07T05:31:56Z",
"mnp_original_carrier": "<string>",
"mnp_ported_at": "2023-11-07T05:31:56Z",
"originalCarrier": "<string>",
"originalMnc": "<string>"
},
"simSwap": {
"swapped": true,
"lastSwapDate": "<string>",
"riskLevel": "low"
},
"roaming": {
"roaming": true,
"servingMcc": "<string>",
"homeMcc": "<string>",
"servingCountry": "<string>"
},
"liveStatus": "yes",
"reachable": true,
"cached": true,
"cachedAt": "2023-11-07T05:31:56Z",
"available": true,
"message": "<string>",
"dataPackages": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123
}
}{}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{}Full phone number intelligence lookup
Full number intelligence (carrier / portability / SIM swap / roaming / live status) for a single E.164 phone number. Uses Devotel HLR as primary and Telnyx as fallback. When fields= is supplied (comma-separated or JSON array), the response also carries a dataPackages map keyed by the requested field names — each entry carries a discriminated status enum (available | coming_soon | not_implemented | error), a reason string, the intended provider, and an optional data payload when realised. The cnam and caller_name (Twilio-compat CNAM alias) fields return the registered caller name in data.caller_name (sourced from the Telnyx caller-name dip); data.caller_name is null when the number has no CNAM record, and the fields fall back to coming_soon only when the dip is not configured. The sms_pumping_risk field (Twilio Lookup v2 SMS-pumping-risk parity) returns a transparent 0-100 fraud score in data.score with a data.risk_level bucket (low/medium/high) and the contributing signals (line_type, line_type_risk, reachable, ported) — derived from the same HLR/Telnyx upstream the lookup already fetched, so fraud/ATO teams can score a number before granting an OTP send. The reassigned_number field (Twilio Lookup v2 US-only Reassigned Number parity) checks the FCC Reassigned Numbers Database (47 CFR § 64.1200(m)) for the TCPA reassigned-number safe harbor — supply consent_date (YYYY-MM-DD) and data carries status (yes = disconnected after consent, no = safe harbor applies, no_data = no record), safe_harbor, and last_disconnect_date; it returns error (consent_date_required) when consent_date is omitted and coming_soon until the RND feed is provisioned. The call_forwarding field (Twilio Lookup v2 forwarding parity) returns a DERIVED, best-effort signal in data.call_forwarding (boolean) inferred from the HLR reachability dip — an unreachable valid line is the classic proxy for an active unconditional divert; it is explicitly flagged data.derived: true with data.confidence: "low" (NOT an operator-asserted forwarding flag, which would need the paid Telnyx add-on) and falls back to coming_soon only when HLR returns no usable reachability signal. The sim_swap field (Twilio Lookup v2 SIM-swap parity) returns the carrier-asserted SIM-swap signal in data — last_swap_date (the most recent SIM-change timestamp), swapped (whether a change falls inside the look-back window), and a risk_level bucket (high within 24h, medium within 7d, low otherwise) — sourced from the GSMA Open Gateway / CAMARA SIM Swap network API so account-takeover and step-up-auth flows can block or challenge high-risk numbers. It falls back to coming_soon only when no CAMARA operator is configured for the deployment. The number_reputation field (Twilio Lookup v2 Number Reputation parity) returns a transparent 0-1 spam/fraud risk score in data.risk_score with a data.risk_bucket (low/medium/high), the data.factors that fired, and the contributing signals (line_type, reachable, ported, sim_swapped) — DERIVED from the same HLR/Telnyx upstream the lookup already fetched (flagged data.derived: true, NOT a paid reputation feed); it falls back to not_implemented only when no usable signal is present. The identity_match field (Twilio Lookup v2 Identity Match parity) matches caller-supplied identity attributes against the mobile operator’s own KYC records via the CAMARA KYC Match network API — supply one or more identity_* attributes (identity_name, identity_given_name, identity_family_name, identity_birthdate, identity_email, identity_id_document) and data carries per-attribute verdicts in data.matches (true/false/not_available), any partial-match data.scores, and an aggregate data.overall_match — never the underlying PII. It returns error (identity_attributes_required) when no attribute is supplied and coming_soon until a CAMARA operator is configured. The live_activity field (Twilio Lookup real-time reachability parity) returns a DERIVED, real-time reachability verdict fused from the live HLR dip — data.active_line (whether the SIM is currently reachable on-network), data.roaming (whether the serving network differs from the home network), data.serving_network_mcc + data.serving_country (the current serving network), data.ported, and a composite data.fraud_risk bucket (low/medium/high/unknown) — so fraud/ATO teams can score real-time reachability before an OTP send; it is flagged data.derived: true (NOT a paid live-activity feed) and falls back to coming_soon only when the upstream returns no usable live signal. Mirrors the Twilio Lookup v2 add-on selector.
curl --request GET \
--url https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/numbers/lookup/{phoneNumber}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": {
"phoneNumber": "<string>",
"valid": true,
"callingCountryCode": "<string>",
"nationalFormat": "<string>",
"carrier": {
"name": "<string>",
"type": "<string>",
"mcc": "<string>",
"mnc": "<string>"
},
"portability": {
"ported": true,
"portedDate": "2023-11-07T05:31:56Z",
"mnp_original_carrier": "<string>",
"mnp_ported_at": "2023-11-07T05:31:56Z",
"originalCarrier": "<string>",
"originalMnc": "<string>"
},
"simSwap": {
"swapped": true,
"lastSwapDate": "<string>",
"riskLevel": "low"
},
"roaming": {
"roaming": true,
"servingMcc": "<string>",
"homeMcc": "<string>",
"servingCountry": "<string>"
},
"liveStatus": "yes",
"reachable": true,
"cached": true,
"cachedAt": "2023-11-07T05:31:56Z",
"available": true,
"message": "<string>",
"dataPackages": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123
}
}{}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{}Authorizations
Dashboard JWT token from Clerk
Headers
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
true, false Path Parameters
Phone number in E.164 format. URL-encode the leading + (or use %2B). The route also accepts an unencoded + for back-compat — decodeURIComponent runs server-side.
Query Parameters
Optional Twilio-compat data-package selector. Comma-separated list of field names from the enumeration below (case-insensitive, deduped server-side, max 16 fields per request). Unknown field names reject the whole request with 422.
Required only when reassigned_number is in fields. The date (YYYY-MM-DD) prior-express consent was obtained or last verified. The FCC reassigned-number safe harbor is evaluated against this date — if reassigned_number is requested without it, that field returns status: error (consent_date_required) while the rest of the response is unaffected.
^\d{4}-\d{2}-\d{2}$Used only when identity_match is in fields. Full registered name to verify against the operator's KYC records. Supply at least one identity_* attribute when requesting identity_match, else that field returns status: error (identity_attributes_required).
Used only when identity_match is in fields. Given (first) name to verify against the operator's KYC records.
Used only when identity_match is in fields. Family (last) name to verify against the operator's KYC records.
Used only when identity_match is in fields. Date of birth (YYYY-MM-DD) to verify against the operator's KYC records.
^\d{4}-\d{2}-\d{2}$Used only when identity_match is in fields. Email address to verify against the operator's KYC records.
Used only when identity_match is in fields. Government ID document reference to verify against the operator's KYC records.