Phone number scam lookup API
Bewary's phone API checks numbers against its scam list, which includes numbers from FTC and FCC complaints and Germany's Federal Network Agency (BNetzA) actions. It returns the country and number type from the numbering plan. With `line_type=true`, it adds the live line type from the carrier network. A number named only as caller ID in unwanted-call complaints carries `PHONE_REPORTED_CALLER_ID`, a caution, and is not listed. A call costs 1 credit (10 with line_type=true), a free key gets 1,000 credits a month, no card, and it answers in median 115 ms.
- Endpoint
- GET
https://api.bewary.app/v1/phone/{number} - Price
- 1 credit, line_type=true 10
- Free key
- 1,000 credits a month, no card
- Speed
- Median 115 ms, measured
- Returns
- verdict, p_scam, entities with typed facts, reason codes
- MCP tool
lookup_phone- Free tool
- Is this number a scam?
Try it
Free from this page: 10 lookups a dayCall it
curl "https://api.bewary.app/v1/phone/%2B18008291040" import requests
r = requests.get("https://api.bewary.app/v1/phone/%2B18008291040", timeout=10)
result = r.json()
print(result["verdict"], result["p_scam"], result["reason_codes"]) const res = await fetch("https://api.bewary.app/v1/phone/%2B18008291040")
const result = await res.json()
console.log(result.verdict, result.p_scam, result.reason_codes) Act on the result
Copy-paste code that turns the answer into a decision. It runs with or without BEWARY_API_KEY. TypeScript uses bewary.d.ts.
import os, requests
from urllib.parse import quote
def caller_label(number):
key = os.environ["BEWARY_API_KEY"] # a free key: bewary.app/account
headers = {"Authorization": f"Bearer {key}"}
r = requests.get("https://api.bewary.app/v1/phone/" + quote(number), headers=headers, timeout=10)
r.raise_for_status()
result = r.json()
if result["entities"][0]["facts"]["listed"]:
return "Reported for scam calls"
return None # no label: not listed is not proof of safe
print(caller_label("+18008291040")) import type { Envelope } from "./bewary"
export async function callerLabel(number: string): Promise<string | null> {
const key = process.env.BEWARY_API_KEY! // a free key: bewary.app/account
const headers: Record<string, string> = { Authorization: `Bearer ${key}` }
const res = await fetch("https://api.bewary.app/v1/phone/" + encodeURIComponent(number),
{ headers, signal: AbortSignal.timeout(10_000) })
if (!res.ok) return null
const e = (await res.json() as Envelope).entities[0]
return e.type === "phone" && e.facts.listed ? "Reported for scam calls" : null
} Response
The fields you will use
verdict- scam when the number is on our list, otherwise usually unknown.
entities[0].facts.listed- On Bewary's scam list.
entities[0].facts.number_type- From the numbering plan: toll_free, mobile, landline and more.
entities[0].facts.line_type- With line_type=true: the live line type.
{ "schema_version": "1.7.0", "request_id": "req_01M69WHKA2ETH25TQA4J813VRP", "checked_at": "2026-10-31T21:06:15Z", "engine": "bewary-engine/3.0.0", "models": { "calibration": "interim-band-v0" }, "input": { "kind": "lookup", "channel": "unknown", "language": null, "region": null }, "verdict": "unknown", "p_scam": 0.2, "risk_score": 20, "confidence": 0, "classification": null, "reason_codes": [], "entities": [ { "id": "e1", "type": "phone", "value": "+18008291040", "normalized": "+18008291040", "role": "mentioned", "verdict": "unknown", "p_scam": 0.2, "risk_score": 20, "reason_codes": [], "facts": { "e164": "+18008291040", "country": "US", "number_type": "toll_free", "original_carrier": null, "line_type": null, "complaints": { "ftc": null, "fcc": null, "callbacks": null, "pushed_by": null }, "honeypot_hits_30d": 0, "listed": false, "public_listing": null, "indexable": false, "target_countries": null, "list_count": null }, "related": [], "datasets": [ { "dataset": "phone_numbering", "coverage": "WW", "in_coverage": true }, { "dataset": "us_numbering", "coverage": "US", "in_coverage": true }, { "dataset": "phone_complaints", "coverage": "US", "in_coverage": true }, { "dataset": "honeypot_lines", "coverage": "US", "in_coverage": true }, { "dataset": "phone_reports_de", "coverage": "DE", "in_coverage": false }, { "dataset": "community_reports", "coverage": "WW", "in_coverage": true } ] } ], "signals": [], "degraded": false, "degraded_reasons": [], "cached": false, "explanation": null} Real responses, captured from the live API on 2026-10-31. Every response has this shape: see Response format.
Phone number facts
Every key is in every response, null when unknown. A key marked Coming stays null until its source ships, so you can code against it now.
| Key | Type | Meaning |
|---|---|---|
e164 | string or null | The number in E.164 form. |
country | ISO code or null | Country from the numbering plan. |
number_type | mobile | landline | voip | toll_free | premium | shared_cost | shortcode | unknown or null | Type from the numbering plan. |
line_type | same values or null | With line_type=true: the live line type from the carrier network. |
listed | boolean or null | On Bewary's scam list. |
complaints | object or null | FTC and FCC complaints from the last 13 months, one entry per source (null when that source has none): count, days, first and last date, subjects, robocall share, the count per day for 90 days and the top five states of the people who complained. |
indexable | boolean or null | Whether the number has a page in the number directory: two independent signals, such as complaints on two or more days, or FTC and FCC complaints. |
original_carrier | string or null | The carrier the number block was first assigned to. |
target_countries | array or null | Countries whose people it is aimed at, from the national lists that name it (PL, TW, DE, US). |
list_count | integer or null | How many lists name it, ours and others'. |
honeypot_hits_30d | integer or null | Calls to our honeypot lines in 30 days. |
Parameters
| Name | Type | Description |
|---|---|---|
numberpath, required | string | The number in E.164 form, e.g. +18008291040. A national number needs region. |
line_typequery | boolean | Add the live line type: mobile, landline or VoIP (10 credits, API key required). Default false. |
regionquery | string | ISO country code for reading a national number, e.g. US. |
Questions
Is there an API that says if a phone number is a scam?
Yes, GET /v1/phone/{number} checks Bewary's scam list. Bewary reads FTC Do Not Call and FCC complaints hourly and Germany's Federal Network Agency (BNetzA) actions daily. Numbers named only as caller ID in unwanted-call complaints stay unknown unless other evidence names them. Your code must never treat unknown as safe.
Can it detect VoIP numbers?
With line_type=true (10 credits, API key), facts.line_type gives the live line type, VoIP included. The free number_type comes from the numbering plan, which for US numbers often cannot tell mobile from landline.
Does it return the owner's name?
No. Bewary never returns a person's name for a number.
Is a listed number always a scammer?
Bewary's scam list includes numbers pushed as callback numbers in calls and numbers named in national lists such as BNetzA's actions against phone numbers. Since contract 1.2.0, a number named only as caller ID carries the caution PHONE_REPORTED_CALLER_ID and stays unknown without a scam listing.
Used for
- Labelling incoming calls in a dialer, CRM or call center.
- Checking the callback number in a suspicious message.
- Flagging VoIP numbers at sign-up.
Reason codes it can return
| Code | Meaning | Severity |
|---|---|---|
LISTED_BLOCKLIST | On scam blocklist | Critical |
PHONE_INVALID | Invalid number | Medium |
PHONE_UNPARSEABLE | Number unreadable | Info |
PHONE_VOIP | VoIP / virtual number | Medium |
PHONE_RISK_FLAGGED | Flagged number | Medium |
PHONE_PUBLIC_SCAM_REPORTS | Reported scam number | Medium |
PHONE_NO_PUBLIC_LISTING | No public listing | Info |
PHONE_FTC_COMPLAINTS | Complaints about this number at the FTC | Medium |
PHONE_FCC_COMPLAINTS | Complaints about this number at the FCC | Medium |
PHONE_HONEYPOT_HIT | Called our honeypot lines | High |
LISTED_CAUTION | On a broad threat list that also holds spam and malware hosts | Medium |
PHONE_REPORTED_CALLER_ID | Shown as the caller ID of complained-about calls, which callers can fake | Medium |
PLATFORM_TAKEDOWN | The hosting platform took it down | High |
PLATFORM_WARNING | The platform shows a phishing or malware warning in front of it | High |
Reserved codes are in the contract, not emitted yet. All reason codes
Updated · This page as Markdown · Changelog