Skip to main content

Official LayerCall client — score an IP, email, phone, domain or a whole signup for fraud in one call. Zero dependencies.

Project description

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")
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

Every method takes strictness (0 lenient → 3 paranoid). It moves the verdict thresholds only; the risk score never changes, so you can re-tune without re-scoring anything.

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

layercall-1.0.0.tar.gz (5.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

layercall-1.0.0-py3-none-any.whl (6.1 kB view details)

Uploaded Python 3

File details

Details for the file layercall-1.0.0.tar.gz.

File metadata

  • Download URL: layercall-1.0.0.tar.gz
  • Upload date:
  • Size: 5.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for layercall-1.0.0.tar.gz
Algorithm Hash digest
SHA256 27d23334528bca6262d2fbfaac57d1f5c00379cd81ab895f78aa7e82e70277da
MD5 162bedc9a99cc646315acb2b2e4eb545
BLAKE2b-256 ac071d9019dfd8bc798310cc1759ed3e7ef250fa424f4bb0ca8583b5821ad0b6

See more details on using hashes here.

File details

Details for the file layercall-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: layercall-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for layercall-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0eb06f02ab881f20fca3cb16f4945e6b68f067ef0a04bf02bbb406140f669cef
MD5 7543f420fc869d69b7d69abe3e346f9f
BLAKE2b-256 ee5459a26cc0ad619750a41a597e02a75a9f344cad52d6f2cd2f6e3bb82134b8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page