Skip to main content

layercall

Official Python client for LayerCall — score an IP, email, phone number, domain, or a whole signup for fraud in a single call.

Zero dependencies. Standard library only. A trust check sits on your signup path, which is the worst place to add a dependency tree that has to resolve against whatever your app already pins.

pip install layercall

Quick start

import os
from layercall import LayerCall

lc = LayerCall(os.environ["LAYERCALL_API_KEY"])

result = lc.score_user(ip=request.remote_addr, email=form["email"])

if result["verdict"] == "review":
    send_otp(form["email"])      # a real user clears it themselves
elif result["verdict"] == "block":
    queue_for_review(result)

Get a free API key — 1,000 lookups a month, no card.

Acting on a verdict

Verdict Do this Not this
allow Let them through
review Step up — OTP, SMS, 3-D Secure Don't reject. This band includes ordinary VPN users.
block Reject, or send to a human queue Don't reject silently

Prefer a challenge over a rejection. A real user clears it in seconds; an attacker cannot. A false positive then costs friction instead of a customer.

Already send an OTP to everyone? Passwordless products can't use an email code as a step-up — it's already mandatory. Score after sign-in and use a different lever: a limited account state, a delayed payout, or a review queue.

Methods

lc.score_ip("185.220.101.1")
lc.verify_email("someone@mailinator.com")
lc.lookup_phone("+14155552671")
lc.lookup_phone("4155552671", country="US")
lc.score_domain("example.com")
# score_device is the one method you cannot try without a browser: it needs a
# real fingerprint and the API correctly refuses anything else. On a TEST key
# these two fixtures work verbatim, so you can call it today and wire up
# /fp.js afterwards.
lc.score_device("0" * 32)                            # clean browser
lc.score_device("f" * 32)                            # headless automation
lc.score_device(device_id, ip=ip, signals=signals)   # real: fingerprint from /fp.js
lc.score_user(ip=ip, email=email, phone=phone, device_id=device_id)
lc.batch("email", ["a@x.com", "b@y.com"])            # up to 500

# AI agents — proof of identity, then your policy applied to it
lc.verify_agent(url=url, headers=headers)            # who is this?
lc.authorize_agent(method=method, url=url, headers=headers)  # may they, here?
lc.get_agent_policy()
lc.set_agent_policy([{"trigger": "crawler", "path": "/api", "action": "deny"}])

# Tell us whether a score was right. Free, and the only thing that improves it.
lc.report_outcome(request_id=r["request_id"], outcome="fraud")

# Report confirmed fraud to the shared reputation network. Live keys only.
lc.report("ip", "185.220.101.1", reason="carding")

Custom rules - your lists always win

A rule overrides the computed score for that value. The kind (ip, cidr, email, domain, phone, asn) is detected from the value unless you force it.

lc.add_rules("block", ["185.220.101.1", "mailinator.com"])
lc.add_rules("allow", "10.0.0.0/8")
lc.add_rules("block", ["AS14061"], kind="asn")

listed = lc.list_rules()
lc.delete_rule(listed["rules"][0]["id"])

# Paste a list - one value per line, or CSV.
lc.import_rules("block", "1.2.3.4\n5.6.7.8\nspam.example")

# Removes EVERY rule on the account. confirm is required, deliberately.
lc.clear_rules(confirm=True)

A pending mailbox

verify_email returns mailbox_status "pending" when the SMTP probe has not finished - it is queued and the answer is there on the next lookup. If you would rather wait for it, say so. It costs 2-10 seconds on a cache miss, which is why it is opt-in:

r = lc.verify_email("someone@example.com", wait_for_mailbox=True)

That is all thirteen. This block used to list seven, with no hint there were more — so a Python developer reasonably concluded that device scoring, agent authorization and outcome feedback were Node-only features. They were not; they were shipped, working and undocumented.

Every scoring method takes strictness (0 lenient → 3 paranoid) — score_ip, verify_email, lookup_phone, score_domain, score_device, score_user and batch. It moves the verdict thresholds only; the risk score never changes, so you can re-tune without re-scoring anything.

The other methods report or configure rather than score, and take no strictness: report, report_outcome, verify_agent, authorize_agent, get_agent_policy, set_agent_policy.

None means unknown, never "no"

signals = lc.score_domain("example.de")["signals"]
signals["newly_registered"]   # None — .de publishes no RDAP, so age is unknown

None means we could not determine it. It is not a negative finding. Treating it as "established" is exactly the mistake the field exists to prevent.

Same for mailbox_exists: Gmail and Yahoo accept mail for addresses that do not exist, so we return None rather than a guess.

Errors

from layercall import LayerCallError

try:
    lc.score_ip(ip)
except LayerCallError as err:
    if err.is_quota:   # 402 — out of quota or spend cap reached
        ...
    if err.is_auth:    # 401/403 — bad or revoked key
        ...
    print(err.request_id)   # quote this in a support ticket
except Exception:
    pass   # fail open: let the signup through

429s and 5xx retry automatically (2 attempts, short backoff). Other 4xx fail fast — they will not succeed on a retry.

Server-side only

An API key in anything a user can read is public and bills to your account.

License

MIT

Release files for layercall 1.2.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for layercall 1.2.9
File Size Uploaded
layercall-1.2.9.tar.gz 12.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for layercall 1.2.9
File Interpreter ABI Platform
layercall-1.2.9-py3-none-any.whl Python 3 none any Details

Total release size:23.9 kB

Release files / layercall-1.2.9.tar.gz

Download URL layercall-1.2.9.tar.gz
Size 12.9 kB
Tags Source
SHA-256 checksum
How to use checksums
58622528c0b4bb5ceed8b6922da2b334493aa3fbc29f24319504a958871ecfe4
BLAKE2b-256 checksum
How to use checksums
b2bc40522c663d7e8bf02eb79a781224a3be09f0fece515f21b085e50243797e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

Release files / layercall-1.2.9-py3-none-any.whl

Download URL layercall-1.2.9-py3-none-any.whl
Size 10.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
849256d1483b35529b5381969a205ee90a36f8bd21adfac50d0e819d37d6e953
BLAKE2b-256 checksum
How to use checksums
364fd955c526fce7cf632aef11d4a5b35ffd45dfd42f03046a0893b46a5f779a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.9 This release

2 release files

1.2.8

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page