Spam I Am

API docs

The Spam I Am API lets your code or AI agent check whether a number shows a spam label on AT&T, Verizon and T-Mobile. You start a check, your calling platform calls each carrier's test line from the number being checked, and you read the result: the label, the caller name and a screenshot from a real phone on each carrier.

Last updated: 2026-10-24

The API can't place calls. The test calls must come from the number you're checking, and we never spoof numbers, so your platform (Twilio, Retell, Vapi, Bland, a dialer or a phone) places them.

Quickstart

1. Start a check

curl -X POST https://ismynumberspam.com/v1/checks \
  -H "Content-Type: application/json" \
  -d '{"number": "2145550100"}'

Without a key this uses the number's free check, which covers every carrier that's online. The answer includes a token. Keep it: it's the only way to read this check's result.

{
 "id": "9f1c...",
 "number": "+12145550100",
 "status": "waiting_for_calls",
 "token": "ct_...",
 "calls": [
  {"carrier": "AT&T", "dial": "+14695550123", "status": "waiting", "seconds_left": 239},
  {"carrier": "Verizon", "dial": "+1...", "status": "waiting", "seconds_left": 239},
  {"carrier": "T-Mobile", "dial": "+1...", "status": "waiting", "seconds_left": 239}
 ],
 "instructions": "From +12145550100, with caller ID showing, call each 'dial' number..."
}

2. Call each test line

From the number being checked, with caller ID showing, call each dial number, one after another. Our phone reads the screen, then sends the call to voicemail, so you can hang up after a few seconds. You have 2 minutes for one carrier, plus 1 minute for each additional carrier.

3. Read the result

Ask for the check every 5 seconds until status is complete:

curl "https://ismynumberspam.com/v1/checks/9f1c...?token=ct_..."
{
 "id": "9f1c...",
 "status": "complete",
 "flagged": true,
 "flagged_on": ["AT&T"],
 "calls": [
  {"carrier": "AT&T", "status": "complete", "flagged": true, "label": "Spam Risk",
   "caller_name": "Dallas, TX", "checked_at": "2026-10-24T18:02:11.000Z",
   "screenshot_url": "https://ismynumberspam.com/v1/checks/9f1c.../screenshots/....jpg?token=ct_..."},
  {"carrier": "Verizon", "status": "complete", "flagged": false, "label": null,
   "caller_name": null},
  {"carrier": "T-Mobile", "status": "incomplete", "reason": "no_call"}
 ],
 "cost": {"free": true, "held_cents": 0, "charged_cents": 0}
}

With a key, send Authorization: Bearer sia_... instead of the token.

Endpoints

POST /v1/checks

Starts a check. Body:

Answers 201 with the check. Without a key, the number must still have its free check.

With a key, the number's free check is used if it hasn't been. After that, the price is held from your balance while the check runs. You're charged only for carriers that return a result.

GET /v1/checks/{id}

The check and each carrier's result. Add ?token=ct_... for a keyless check. While any carrier is still waiting, the answer has a Retry-After: 5 header.

Each entry in calls:

FieldMeaning
carrierAT&T, Verizon or T-Mobile
dialThe test line to call for this carrier
statuswaiting, complete or incomplete
seconds_leftWhile waiting: time left to place the call
flaggedWhen complete: true if the label is a spam warning
labelWhen complete: the label shown, such as "Spam Risk", or null
caller_nameWhen complete: the caller name shown, or null
reasonWhen incomplete: no_call (no call arrived in time) or unreadable_screen
screenshot_urlThe incoming-call screen, as a JPEG
checked_atWhen the call rang

At the top level, flagged is true if any carrier shows a spam label, false if none do, and null if no carrier returned a result. flagged_on lists the carriers that do.

**Incomplete with no_call, even though you dialed from the right number with caller ID on?** The carrier may have blocked the call before it rang. Treat that as more urgent than a label, and check your logs for SIP 603+. What 603+ means

GET /v1/checks/{id}/screenshots/{result}.jpg

The screenshot. Use screenshot_url from the check; it already carries the token for a keyless check.

GET /v1/balance

Needs a key. Your balance, the amount held for checks in progress, and what's available, in cents. Also this key's spending limit (key_spend_limit_cents, null for none) and what it has spent (key_spent_cents).

POST /v1/handoffs and GET /v1/handoffs/{id}

Ask your human to approve spending. See below.

GET /v1/coverage

No key needed. Which carriers are online now, prices in cents by number of carriers, whether the free first check is on, and the dialing window.

Webhooks

Pass webhook_url when you start a check, and we POST the finished check to it: once every carrier has a result or its dialing window has ended.

{"type": "check.completed", "check": { ...the same JSON as GET /v1/checks/{id}... }}

Ask your human to approve spending

After a number's free check, checks cost money. An agent shouldn't pay or handle card details. Instead it asks its human:

curl -X POST https://ismynumberspam.com/v1/handoffs \
  -H "Content-Type: application/json" \
  -d '{"reason": "Check our sales line before Monday's campaign", "amount_cents": 500}'
{
 "id": "4c7e...",
 "status": "pending",
 "approve_url": "https://ismynumberspam.com/approve/4c7e...",
 "token": "ht_...",
 "expires_at": "2026-10-25T18:00:00.000Z"
}
  1. **Show approve_url to your human.** They sign in or create an account, add funds if needed, set a spending limit and approve (or decline).
  2. Ask for the request every 5 seconds: GET /v1/handoffs/{id}?token=ht_.... Its status becomes approved, declined or expired (after 24 hours).
  3. **When it's approved, the answer has api_key,** shown once. Store it and send it as Authorization: Bearer sia_.... It can spend up to the limit your human set.

All fields are optional: reason (up to 300 characters, shown to your human), number (the number you want to check) and amount_cents (the amount you're asking for; suggested as the limit).

Already have a key that hit its limit? Send the request with your key. Approving it sets your key's new limit; no new key is made. Read it with the same key.

Errors

Errors use one format:

{"error": {"code": "too_soon", "message": "(214) 555-0100 was checked recently..."}}
StatusCodeWhat to do
400invalid_numberSend a 10-digit US number
400invalid_carriersUse AT&T, Verizon or T-Mobile
400invalid_jsonSend a JSON object
400test_lineThat's one of our test lines. Send the number you'll call from
401api_key_requiredSend a key
401invalid_api_keyThe key is wrong or revoked. Make a new one
400invalid_webhook_urlUse a public https address
402insufficient_fundsAsk your human to add funds (approval request). The error has price_cents and available_cents
402key_limitThis key reached its spending limit. Ask your human to approve more. The error has limit_cents and spent_cents
404not_foundWrong id, or the check belongs to another key or token
409free_check_usedThis number had its free check. Use a key
429too_soonEach number can be checked once an hour. Wait for Retry-After seconds
429too_many_openFinish or let your open checks expire first
429daily_limitDaily check limit reached
429free_limitToo many keyless checks from your network today. Use a key
429handoff_limitToo many approval requests from your network today
503no_linesNo test line is online for those carriers. Try again later

Rules

Pricing

The first check on any number is free. After that, $0.25 for one carrier or $0.40 for two or three, from the same balance you use on the website. Incomplete carriers are free. Pricing

MCP

Agents that use Model Context Protocol can connect to https://ismynumberspam.com/mcp instead. MCP server

FAQ

Do I need a key?

Not for the first check on a number. After that, sign up, add funds and make a key on the Balance page. An agent can also ask its human for a key with an approval request.

Can I cap what an agent spends?

Yes. Every key can have a spending limit. Set it when you make the key on the Balance page, or when you approve an agent's request.

Can the API place the test calls for me?

No. The calls must come from the number you're checking, so your own platform places them. We never spoof numbers.

How do I get the result?

Ask for the check every 5 seconds until its status is complete, or pass a webhook_url and we'll send it to you. Results usually arrive about 5 seconds after each call rings.

What does an API check cost?

The same as on the website: $0.25 for one carrier or $0.40 for two or three. Carriers that return no result are free.

See what your number shows

Call our real AT&T, Verizon and T-Mobile phones and see the label, caller name and a screenshot. The first check of any number is free.

Check your number free