API reference

Base URL: your BurnGuard host, e.g. https://YOUR-BURNGUARD-HOST. All endpoints accept and return JSON (UTF-8). Request bodies are capped at 16 KB.

Authentication

Send your secret key as a bearer token. Secret keys belong on your server only. Never ship them to a browser or mobile app.

Authorization: Bearer bg_sk_your_secret_key

POST /v1/check

Score a signup, login or trial start. Counts as one check against your monthly quota.

Request body

Field Type Required Notes
email string yes The address the user typed. We normalize it for you.
event string yes signup, login or trial_start.
ip string recommended The end user's IP (IPv4 or IPv6), not your server's.
device_token string recommended The bg_device value from the SDK.
user_agent string optional The end user's User-Agent header.
external_id string optional Your user id. Lets you link usage to this check.

Optional header Idempotency-Key: <unique string> returns the original result if you retry the same request.

curl https://YOUR-BURNGUARD-HOST/v1/check \
  -H "Authorization: Bearer $BURNGUARD_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event":"signup","email":"j.o.h.n+42@gmail.com","ip":"203.0.113.7","device_token":"dv_3f9a…"}'

Response

{
  "id": "chk_9d1c…",
  "decision": "allow",
  "would_decision": "limit",
  "mode": "monitor",
  "score": 41,
  "recommended_credit_fraction": 0.1,
  "reasons": [
    { "code": "plus_or_dot_alias", "weight": 15, "detail": "Gmail dots/+tag removed: john@gmail.com" },
    { "code": "datacenter_ip", "weight": 40, "detail": "IP belongs to a hosting provider (DigitalOcean)" }
  ],
  "normalized_email": "john@gmail.com",
  "cluster_size": 3
}
Field Notes
decision What to act on: allow, limit, review or block. In monitor mode this is always allow.
would_decision What BurnGuard decides with your thresholds, regardless of mode.
mode monitor or enforce (set per project in the dashboard).
score 0–100. Signals combine so several weak ones add up but never exceed 100.
recommended_credit_fraction 0–1. How much of your free tier to grant now. 1 for allow, a fraction for limit, 0 for review and block.
reasons Every signal that fired, with its weight and a human-readable detail.
normalized_email Lowercased, Gmail dots and +tags removed. Use it to spot duplicates in your own data.
cluster_size Distinct accounts linked to this one by normalized email, device or IP in the last 30 days, including this one.
quota_exceeded Present and true when you are over your plan's monthly checks. The decision is then always allow.

Decisions and default thresholds

Decision Default score Suggested handling
allow below 30 Full free tier.
limit 30 to 49 Grant recommended_credit_fraction of the credits; unlock the rest after card, phone or account age.
review 50 to 74 Create the account but require verification before any credits.
block 75 and above Refuse the signup with a neutral message.

Thresholds are configurable per project. Allowlist matches always return allow; blocklist matches always return block.

Reason codes

Code Meaning
disposable_domain Known throwaway inbox provider.
no_mx The domain can't receive email (no MX record).
random_local_part Random-looking username on a free or disposable provider.
plus_or_dot_alias Gmail dots or a +tag were removed during normalization.
normalized_email_reuse The same normalized email already signed up in this project.
datacenter_ip IP belongs to a cloud or hosting provider.
vpn_or_proxy_ip IP is in a known commercial VPN range.
tor_exit IP is a Tor exit node.
ip_velocity / subnet_velocity Many signups from the same IP or /24 in the last hour.
device_reuse The same device token is linked to several different emails.
device_velocity Several signups from one device in the last hour.
automation_user_agent Headless browser, curl, python-requests and similar.
missing_device No device token although this project normally sends one.
allowlist / blocklist Matched one of your lists.

POST /v1/feedback

Tell BurnGuard whether a check was right. Free (doesn't count against quota).

{ "check_id": "chk_9d1c…", "label": "legit" }

label is fraud or legit. legit adds the normalized email to the project's allowlist; fraud adds the device and normalized email to the blocklist. Returns { "ok": true }.

POST /v1/usage

Report credits a user consumed so the dashboard can show dollars burned by flagged accounts. Free (doesn't count against quota).

{ "external_id": "user_123", "cost_cents": 42, "units": 2100 }
Field Notes
external_id The same id you sent on /v1/check.
cost_cents What this usage cost you, in cents (integer ≥ 0).
units Optional: tokens or credits, for your own reference.

Without usage reports, the dashboard estimates savings as flagged signups × your cost per free account (set in project settings).

Errors

Errors use one shape:

{ "error": { "code": "unauthorized", "message": "Missing or invalid API key" } }
HTTP Code When
400 invalid_request Missing or malformed fields.
401 unauthorized Missing, invalid or revoked secret key.
404 not_found Unknown check id (feedback).
429 rate_limited Bursting above the per-key rate limit. Back off and retry.
503 db_unavailable Temporary storage issue on our side.
500 internal Something broke on our side.

Fail open

BurnGuard should never be the reason a real user can't sign up. In every integration:

  1. Set a short timeout (1–1.5 seconds).
  2. Treat timeouts, network errors, 429 and 5xx as allow.
  3. Log the failure so you notice.

Going over your monthly quota doesn't break anything either: the API keeps answering allow with quota_exceeded: true.

Free tool endpoints

The public tools on this site use GET /v1/public/email?email= and GET /v1/public/ip?ip=. They need no key, are heavily rate-limited per visitor, store nothing and only cover email and network signals. Use /v1/check in production.