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.1.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.1-py3-none-any.whl (6.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: layercall-1.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 edc1f6f216de86fc83b4a042e3f4566b95c5dce75b895c094a919d2e10918eda
MD5 44c93a93a882a9bb78474145ad8c0be6
BLAKE2b-256 2b4c75b640a16ee10a5094c34634e9d8768c560800730212444724635798c4af

See more details on using hashes here.

File details

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

File metadata

  • Download URL: layercall-1.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 97e9bbf3b9c19088339b3ac8c260534dfca6d679d1c0fc591ae50ef15c462db8
MD5 500a0ae7385da978c8a390bd73fcc547
BLAKE2b-256 29451a1d5065c52afe550db5c4bc75a2a0221ada7c319c049b89ee7b052ab42c

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