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.1.0.tar.gz (6.5 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.1.0-py3-none-any.whl (6.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for layercall-1.1.0.tar.gz
Algorithm Hash digest
SHA256 bcbd3dad7fdcf243dae946288c1ebccb5c5ed2884123e788c9e3ed928fef91fc
MD5 5e68cac71ab457c06f2960d057b97020
BLAKE2b-256 af6e43a453786bd46cd48d521061ce05e03f89ded3e908b9833931be72b49593

See more details on using hashes here.

File details

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

File metadata

  • Download URL: layercall-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.8 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ff90eb7ce9502357be7faf36dac52824305c5cd7b978fa30a6944decd623d684
MD5 affc9cad09c62e63e157e29e2e4f8192
BLAKE2b-256 64bf0d662bd1241e269cb9ca9bee5fffc3bac138aa1d9e9e579eb55ceebf726e

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