Developer Guide
Node.js integration guide
A minimal Telebase client in Node.js needs nothing beyond the built-in fetch: URL-encode the phone number, 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 encodeURIComponent to URL-encode the phone number before building the request URL. 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. encodeURIComponent handles this correctly.
const API_KEY = "tb_live_xxxxxxxxxxxxxxxxxxxxxxxx"; const BASE_URL = "https://telebase.fatcatremote.com/api/lookup"; async function lookup(phoneNumber) { const encoded = encodeURIComponent(phoneNumber); const response = await fetch(`${BASE_URL}?phone=${encoded}`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); if (!response.ok) { throw new Error(`Lookup failed with status ${response.status}`); } return response.json(); } const result = await lookup("+447700900000"); console.log(result.carrier, result.numberType, result.simSwap);
Handling errors explicitly
fetch does not throw on a non-200 response, it resolves normally, so checking response.ok and branching on response.status is the right place to distinguish the errors your onboarding or authentication flow needs to react to differently.
async function lookup(phoneNumber) { const encoded = encodeURIComponent(phoneNumber); const response = await fetch(`${BASE_URL}?phone=${encoded}`, { headers: { Authorization: `Bearer ${API_KEY}` }, }); if (response.status === 401) { throw new Error("Missing or malformed API key"); } if (response.status === 400) { throw new Error(`Invalid phone number: ${phoneNumber}`); } if (response.status === 402) { throw new Error("Account balance is at zero, top up via the dashboard"); } if (!response.ok) { throw new Error(`Unexpected status ${response.status}`); } 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. Reserve retries for genuinely transient failures: network errors and 5xx responses from the server. A short exponential backoff with a small number of attempts is enough for most integrations.
function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function lookupWithRetry(phoneNumber, maxAttempts = 3) { for (let attempt = 0; attempt < maxAttempts; attempt++) { try { return await lookup(phoneNumber); } catch (err) { const isLastAttempt = attempt === maxAttempts - 1; const isTransient = err.message.includes("Unexpected status 5") || err.name === "TypeError"; if (!isTransient || isLastAttempt) throw err; await sleep(2 ** attempt * 1000); // 1s, 2s, 4s } } }
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.