# SMS short code lookup API

Bewary's short code API tells you which company sends texts from a US short code, such as 86006 for Bank of America, and whether the code is legitimate, shared by several senders or used for scams. Scam texts often name a real bank's code, so a real code mentioned inside a message is never proof on its own. A call costs 1 credit, a free key gets 1,000 credits a month, no card, and it answers in median 113 ms.

Updated 2026-10-30.

## At a glance

- Endpoint: GET https://api.bewary.app/v1/shortcode/{country}/{code}
- Price: 1 credit
- Free key: 1,000 credits a month, no card
- Speed: Median 113 ms, measured
- Returns: verdict, p_scam, entities with typed facts, reason codes
- MCP tool: lookup_shortcode
- Free tool: Short code directory, https://bewary.app/shortcodes

## Used for

- Verifying the sender of a one-time code or a fraud alert.
- Messaging platforms labelling short-code senders.
- Support teams answering "is 86006 really my bank?"

## Call it

curl:

```bash
curl "https://api.bewary.app/v1/shortcode/US/86006"
```

Python:

```python
import requests

r = requests.get("https://api.bewary.app/v1/shortcode/US/86006", timeout=10)
result = r.json()
print(result["verdict"], result["p_scam"], result["reason_codes"])
```

JavaScript:

```javascript
const res = await fetch("https://api.bewary.app/v1/shortcode/US/86006")
const result = await res.json()
console.log(result.verdict, result.p_scam, result.reason_codes)
```

## Act on the result

Python:

```python
import os, requests

def short_code_sender(code):
    key = os.environ["BEWARY_API_KEY"]          # a free key: bewary.app/account
    headers = {"Authorization": f"Bearer {key}"}
    r = requests.get(f"https://api.bewary.app/v1/shortcode/US/{code}", headers=headers, timeout=10)
    r.raise_for_status()
    facts = r.json()["entities"][0]["facts"]
    return facts["status"], (facts["operator"] or {}).get("name")

print(short_code_sender("86006"))   # ('legitimate', 'Bank of America')
```

TypeScript, with the types from https://bewary.app/types/bewary.d.ts:

```typescript
import type { Envelope } from "./bewary"

export async function shortCodeSender(code: string) {
  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/shortcode/US/${encodeURIComponent(code)}`,
    { headers, signal: AbortSignal.timeout(10_000) })
  if (!res.ok) throw new Error(`Bewary ${res.status}`)
  const e = (await res.json() as Envelope).entities[0]
  if (e.type !== "shortcode") throw new Error("unexpected entity")
  return { status: e.facts.status, sender: e.facts.operator?.name ?? null }   // operator is null for shared codes
}
```

## The fields you will use

- `entities[0].facts.status`: legitimate, mixed (shared), scam or unknown.
- `entities[0].facts.operator`: The company that sends from it, with its brand id.
- `verdict`: safe for a legitimate code, scam for a scam code, unknown for a shared or unlisted code.

## Example response: safe

Request: `GET /v1/shortcode/US/86006`. Captured from the live API on 2026-10-31.

```json
{
  "schema_version": "1.7.0",
  "request_id": "req_01M69WHRF89N0KE4G2QYZ013GE",
  "checked_at": "2026-10-31T21:06:18Z",
  "engine": "bewary-engine/3.0.0",
  "models": {
    "calibration": "interim-band-v0"
  },
  "input": {
    "kind": "lookup",
    "channel": "unknown",
    "language": null,
    "region": null
  },
  "verdict": "safe",
  "p_scam": 0.0013,
  "risk_score": 0,
  "confidence": 1,
  "classification": null,
  "reason_codes": [
    "SHORTCODE_LEGITIMATE"
  ],
  "entities": [
    {
      "id": "e1",
      "type": "shortcode",
      "value": "86006",
      "normalized": "86006",
      "role": "mentioned",
      "verdict": "safe",
      "p_scam": 0.0013,
      "risk_score": 0,
      "reason_codes": [
        "SHORTCODE_LEGITIMATE"
      ],
      "facts": {
        "code": "86006",
        "country": "US",
        "status": "legitimate",
        "operator": {
          "name": "Bank of America",
          "brand_id": "bankofamerica"
        },
        "legit_uses": null,
        "reports_30d": null
      },
      "related": [],
      "datasets": [
        {
          "dataset": "shortcodes",
          "coverage": "US",
          "in_coverage": true
        },
        {
          "dataset": "community_reports",
          "coverage": "WW",
          "in_coverage": true
        }
      ]
    }
  ],
  "signals": [
    {
      "code": "SHORTCODE_LEGITIMATE",
      "entity": "e1",
      "severity": "info",
      "weight": 0,
      "source_class": "first_party",
      "p": null,
      "dataset": "shortcodes",
      "coverage": "US",
      "evidence": {}
    }
  ],
  "degraded": false,
  "degraded_reasons": [],
  "cached": false,
  "explanation": null
}
```

## SMS short code facts

Every key is in every response, null when unknown. Keys marked coming stay null until their source ships.

| Key | Type | Meaning |
|---|---|---|
| `code` | string or null | The short code. |
| `country` | ISO code or null | The country it is registered in. |
| `status` | legitimate \| mixed \| scam \| unknown or null | mixed: a shared code used by several senders. |
| `operator` | object or null | The company that sends from it, with its brand id. null when no single company does, which today is every shared and scam code in the directory. |
| `legit_uses` | array or null | What the operator sends: otp, fraud_alert, account_alert, marketing, delivery and more. Coming: null for now. |
| `reports_30d` | integer or null | Reports in 30 days. Coming: null for now. |

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `country` | path | string | yes | ISO country code. US only for now. |
| `code` | path | string | yes | The 5 or 6 digit short code. |

## Questions

### How do I find out who sends texts from a short code?

GET /v1/shortcode/US/{code}. facts.operator names the company and facts.status says whether the code is legitimate, shared (mixed) or a scam code.

### Which short codes are covered?

US codes in the directory at bewary.app/shortcodes, which grows every week. An unlisted code answers status unknown and verdict unknown, never safe.

### What about shared short codes?

A code that several companies send from has status mixed and answers unknown: the code alone cannot tell you who sent a message. operator is null when no single company sends from it.

### A message names my bank's real short code. Is it safe?

Not on its own. Scam texts copy real codes to look genuine. Look up the link or the number the text asks you to use: that is where a scam text gives itself away.

## Reason codes it can return

`LISTED_BLOCKLIST`, `SHORTCODE_LEGITIMATE`, `SHORTCODE_MIXED_USE`, `SHORTCODE_SCAM`, `SHORTCODE_UNREGISTERED`, `LISTED_CAUTION`, `PLATFORM_TAKEDOWN`, `PLATFORM_WARNING`
