# Keys, limits and errors

Every call needs an API key, and a free key gets 1,000 credits a month, no card. Send it as Authorization: Bearer or X-Api-Key. Errors have a stable code to branch on.

Updated 2026-10-30.

## Every call needs a key

Since November 1, 2026 every API call, MCP tool call and CLI command needs an API key, and a call without one answers `401` with a link to a free key. A free key gets 1,000 credits a month with no card, on every endpoint: deep checks, the live phone line type, batch requests, related domains, watches and events, bulk files and backtests included.

The free checkers on bewary.app run in your browser without a key, at 10 checks a day per visitor. They are for a person checking a link or a number, not an allowance for code.

## Your key

Create a key at [bewary.app/account](/account). You sign in with your email, with no password. Send it in either header:

```bash
curl "https://api.bewary.app/v1/domain/paypal-login-secure.top" \
  -H "Authorization: Bearer $BEWARY_API_KEY"

curl "https://api.bewary.app/v1/domain/paypal-login-secure.top" \
  -H "X-Api-Key: $BEWARY_API_KEY"
```

A key looks like `bw_<id>_<secret>`. It is shown once, when you create it. We store only a hash of it, so a lost key cannot be recovered, only revoked and replaced. The same key works for the MCP server. The [privacy policy](/privacy) lists what each call keeps, and the [terms](/terms) say what you may build with the API.

## Credits

Every call costs credits from one balance:

| Call | Credits |
|---|---|
| Lookup: link, domain, IP, phone, short code, email, wallet, IBAN, app, payment handle | 1 |
| Phone lookup with `line_type=true` | 10 |
| Link or domain lookup with `deep=true` | 30 |
| Batch | 1 per valid item |
| Assess an account (`POST /v1/assess`) | 1 per valid field |
| Related domains | 5 a page |
| Watch a domain, number, wallet or brand | 1 a day per watch, charged a day ahead. A brand watch also costs 1 per lookalike event |
| Bulk files | 5,000 for a day pass: every format, as many downloads as you like that UTC day |
| Backtest | 1,000 items free a month, then 1 per item |
| Listing watches, reading events, webhooks | free |

Credits are taken before the work starts and given back if the call fails on our side. With a key, every response carries `X-Credits-Remaining`. Prepaid credit packs are on the [pricing page](/pricing). Their credits never expire.

## Rate limits

A key can make 600 requests a minute. Over the limit, the API answers `429` with a `Retry-After` header in seconds.

## Errors

An error has an HTTP status and a body like this. `code` is stable and safe to branch on. `message` is for people and may change.

```json
{
  "error": {
    "code": "invalid_input",
    "message": "not a domain name",
    "request_id": "req_01M5JT0G519116G5779GDJYP2V"
  }
}
```

| HTTP | `code` | What to do |
|---|---|---|
| 400 | `invalid_input` | The value is not a valid domain, URL, number or address. Fix it and retry. |
| 400 | `unsupported_type` | A chain or country we do not cover yet. |
| 401 | `unauthorized` | The key is missing, revoked or wrong, or the option needs a key. |
| 403 | `forbidden` | The key is not enabled for this, such as bulk delivery. |
| 402 | `quota_exceeded` | The key is out of credits. Buy a credit pack, or wait for next month's free credits. |
| 404 | `not_found` | No watch, webhook or backtest with that id on this account. |
| 410 | `gone` | The endpoint was retired, like the message and screenshot checks on October 30, 2026. The message names what to call instead. |
| 413 | `input_too_large` | The backtest upload is over 2 MB. |
| 429 | `rate_limited` | Too many requests a minute. Wait for `Retry-After`. |
| 500 | `internal` | Our fault. The credits were given back. Retry once. |
| 503 | `degraded_unavailable` | A source or billing is down for a moment. Retry later. |

Send us the `request_id` from the body or the `X-Request-Id` header when you report a problem.
