Developer Guide
Python integration guide
A minimal Telebase client in Python is a single function: build the request URL with the phone number URL-encoded, send it with a Bearer token, and parse the JSON response. This page covers that function, the three error responses worth handling explicitly, and a simple retry pattern for transient network failures.
A minimal client
Use the standard library's urllib.parse.quote to URL-encode the phone number, and requests for the HTTP call. The + in an E.164 number must become %2B; passing a raw + in a query string is interpreted as a space and will produce a failed or incorrect lookup.
import requests from urllib.parse import quote API_KEY = "tb_live_xxxxxxxxxxxxxxxxxxxxxxxx" BASE_URL = "https://telebase.fatcatremote.com/api/lookup" def lookup(phone_number: str) -> dict: encoded_number = quote(phone_number, safe="") response = requests.get( f"{BASE_URL}?phone={encoded_number}", headers={"Authorization": f"Bearer {API_KEY}"}, timeout=10, ) response.raise_for_status() return response.json() result = lookup("+447700900000") print(result["carrier"], result["numberType"], result["simSwap"])
quote(phone_number, safe="") handles the + to %2B conversion correctly, so there is no need to encode it manually.
Handling errors explicitly
response.raise_for_status() will raise an HTTPError for any non-200 response, but it is worth catching that and branching on the status code so your onboarding or authentication flow can respond appropriately rather than surfacing a raw exception.
def lookup(phone_number: str) -> dict: encoded_number = quote(phone_number, safe="") response = requests.get( f"{BASE_URL}?phone={encoded_number}", headers={"Authorization": f"Bearer {API_KEY}"}, timeout=10, ) if response.status_code == 401: raise RuntimeError("Missing or malformed API key") if response.status_code == 400: raise ValueError(f"Invalid phone number: {phone_number}") if response.status_code == 402: raise RuntimeError("Account balance is at zero, top up via the dashboard") response.raise_for_status() # catches anything else non-200 return response.json()
What each status means
- 401: the
Authorizationheader is missing or malformed. Check it reads exactlyBearer tb_live_...with one space after Bearer. - 400: the phone number failed validation, commonly a missing country code, a raw
+instead of%2B, or a number outside valid E.164 length. - 402: the account balance is at zero. Top up via the dashboard before retrying.
A retry pattern for transient failures
401, 400 and 402 will not resolve themselves on retry, since each reflects something about the request or account that needs fixing first. Retries are worth applying only to genuinely transient failures: network timeouts, connection errors, and 5xx responses from the server. A short exponential backoff with a small number of attempts is enough for most integrations.
import time def lookup_with_retry(phone_number: str, max_attempts: int = 3) -> dict: for attempt in range(max_attempts): try: return lookup(phone_number) except (requests.ConnectionError, requests.Timeout): if attempt == max_attempts - 1: raise time.sleep(2 ** attempt) # 1s, 2s, 4s except requests.HTTPError as exc: if exc.response.status_code >= 500 and attempt < max_attempts - 1: time.sleep(2 ** attempt) continue raise
Do not retry on 401, 400 or 402: fix the API key, the phone number format, or the account balance instead.
Signals available today
Live in every response
- active: whether the number is currently reachable on the carrier network
- carrier: the network operator serving the number
- country: ISO country code of the number
- numberType: mobile, landline, fixedVoip, nonFixedVoip, tollFree or voicemail
New to the API entirely? Start with the quickstart guide for the first request end to end.