Live: Tor + abuse feeds refreshed every 6 hours

LayerCall

Quickstart

Get a key, make one call, read the verdict.

Step 1 — get your key. Create a free API key (1,000 lookups/month, no card). Then pass it in the X-Api-Key header on every request below.

Strictness. Add &strictness= (0–3) to any scoring endpoint to tune how aggressively verdicts flip — 0 lenient (fewest false positives), 1 balanced (default), 2 strict, 3 paranoid. The risk_score stays the same; only the verdict thresholds move.

curl "https://www.layercall.com/v1/score/ip?ip=185.220.101.1" \
  -H "X-Api-Key: tl_live_your_key"
{
  "ip": "185.220.101.1",
  "risk_score": 60,
  "signals": {
    "is_vpn": true,
    "is_proxy": true,
    "is_datacenter": true,
    "is_tor": true,
    "recent_abuse": false,
    "is_hijacked_netblock": false
  },
  "geo": {
    "country": "DE",
    "city": "Berlin",
    "asn": "AS60729",
    "isp": "Stiftung Erneuerbare Freiheit"
  },
  "vpn_provider": null,
  "hijacked_source": null,
  "verdict": "review",
  "abuse_reports": 0
}

Endpoint reference

Full request and response detail for every endpoint lives on its own page, so this one stays readable.

Node.js

const res = await fetch("https://www.layercall.com/v1/score/user", {
  method: "POST",
  headers: {
    "X-Api-Key": process.env.LAYERCALL_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ ip, email, phone }),
});
const { verdict, risk_score, top_signals } = await res.json();

if (verdict === "block") {
  // reject the signup or require step-up verification
}

Python

import os, requests

res = requests.post(
    "https://www.layercall.com/v1/score/user",
    json={"ip": ip, "email": email, "phone": phone},
    headers={"X-Api-Key": os.environ["LAYERCALL_API_KEY"]},
    timeout=5,
)
data = res.json()
if data["verdict"] == "block":
    ...  # reject or challenge

Errors

  • 400 — the request was understood and refused. The codes are: invalid_ip, invalid_email, invalid_phone, invalid_domain, invalid_device_id, invalid_country, invalid_field_type (a number where text belongs — the response names the field), invalid_body, batch_too_large, missing_parameter when nothing was supplied at all, and invalid_parameter for anything else. Retrying the same request will not help.
  • 401 — no API key provided (missing_api_key). Both www.layercall.com and layercall.com serve /v1 directly, so either host works and neither redirects your call. The Bearer prefix is optional and case-insensitive, so it is never the cause either: this error means no key header reached us at all. If you are sure you sent one, check whether a proxy, gateway or framework is stripping AuthorizationX-Api-Key: YOUR_KEY is accepted as an alternative and is less often filtered.
  • 403 — invalid or revoked API key (invalid_api_key), or a test key on an endpoint that refuses them (test_key_not_allowed).
  • 404 — no such endpoint (not_found, with error: "unknown_endpoint"). The body lists every real endpoint with the methods it accepts.
  • 402 — monthly plan quota exceeded (quota_exceeded), the account is paused after a failed payment (account_paused), your own spend cap stopped it (spend_cap_reached), or the feature belongs to a higher plan (plan_required). Retrying will not help; upgrade, raise the cap, or update your card.
  • 429 — too many requests this minute (rate_limited). Honour Retry-After and retry.
  • 405 — the endpoint exists but not for that HTTP method (method_not_allowed). The body carries allow, the methods it does take, and the same list is in the Allow header. Most take GET or POST but not both.
  • 500 — something failed on our side (internal_error). Include request_id when reporting it; every error response carries one.

Recommended integration pattern

Call /v1/score/user at signup or checkout with everything you have, before creating the account or charging the card.

VerdictDo thisNot this
allowLet them through with no friction.
reviewStep up — email OTP, SMS, or 3-D Secure at checkout. A real user clears it themselves in seconds.Don’t reject. This band includes every commercial VPN user, most of whom are ordinary customers.
blockReject, or send to a human review queue if the account is worth the handling cost.Don’t reject silently — say something, or your support team learns about it from a bad review.

Prefer step-up over rejection. A challenge lets a legitimate user clear the flag themselves while still stopping an attacker who cannot pass it, so a false positive costs seconds instead of a customer. This is what the large fraud platforms converged on: Stripe Radar blocks only above 75 out of 99 and hands 65–74 to a review queue rather than refusing it, and requests 3-D Secure instead of declining where it can. Sift models the middle band as “Watch”, which explicitly includes asking for mobile verification rather than blocking.

If you already send an OTP to everyone, your step-up is something else. Passwordless and magic-link products cannot use an email code as conditional friction, because it is already mandatory and it happens before the account exists — there is nothing left to escalate to. Score after sign-in instead and use a different lever on review: hold the account in a limited state, delay a payout or a first send, require SMS or a card on file, or simply queue it for a look. We run exactly this way ourselves, which is why our own scoring is observational rather than a gate.

Fail open. If this API is unreachable, let the signup proceed. Losing a real customer to our downtime is a worse outcome than admitting one fraudster, and it is the failure mode you will never see in your metrics.

Measure before you tighten. Log the verdict without acting on it for a week or two, then compare it against the accounts that turned out fine. If you already verify email with a one-time code, everyone who completes it is real by the only test that matters at signup, so any block on that group is a false positive you can count exactly. Tune strictness against that number rather than a guess.

OpenAPI specification

The full API is described by an OpenAPI 3.1 document at /openapi.json. Generate a typed client in any language with openapi-generator, or point an AI coding assistant at it to scaffold your integration.

curl https://www.layercall.com/openapi.json -o layercall.json

Postman

A ready-made collection covering every endpoint, each request pre-filled with input that actually returns signals — a Tor exit node, a disposable mailbox — rather than a clean value that tells you nothing. Import the URL below, set the apiKey variable, and send. A tl_test_ key works for everything except the two endpoints that write to the shared reputation network, which say so on the request itself.

https://www.layercall.com/layercall.postman_collection.json

In Postman: Import → Link, then paste that URL. The collection is generated from the OpenAPI document above and tested against production, so it cannot describe an endpoint this API does not have.