Pricing Documentation Sign up Log in

Gates (beta)

Migrate from Email & Domain

The Gates Decision API replaces manual logic built around the /email and /domain endpoints. Instead of pulling raw signals and writing your own logic, you define reusable rules directly in the dashboard and let the Gate decide.

This guide shows how to migrate existing integrations in a few steps.

1. Create a Gate

Start by creating a new Gate for the flow you want to protect.
See Quickstart for setup.

2. Rebuild your checks as rules

Take the logic you currently apply after calling /email or /domain, for example:

  • if disposable → block
  • if spam → block
  • etc...

Then recreate it as rules inside your Gate.
Each rule can check one or more fields (like domain.mx, email.role_account) and choose an action: allow, block, or challenge.
See Rules & Conditions for field references.

3. Update your API integration

Replace your GET /email or GET /domain calls with a POST to your Gate’s Decision endpoint:

curl -X POST "https://api.usercheck.com/v0/gates/{gate_id}/decisions" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{ "email": "[email protected]" }'

Swap "email" for "domain" if that’s your input.

The response contains three key objects:

{
  "decision": {
    "action": "block",
    "matched_rule": { "name": "Block domains with no MX records" }
  },
  "signals": {
    "email": { "mx": false, "disposable": false },
    "domain": { "mx": false, "spam": false }
  }
}
  • decision.action — the Gate’s decision (allow, block, or challenge)
  • matched_rule — which rule triggered, including its name and optional message
  • signals — the same diagnostic data you’d get from /email or /domain

The Gate already applies your rules and returns a verdict. Treat signals as informational only.

4. Example migration

Before: manual logic

response = requests.get(
    f"https://api.usercheck.com/email/{email}",
    headers={"Authorization": f"Bearer {API_KEY}"},
)
data = response.json()

if data.get("disposable"):
    raise SignUpError("Disposable emails are not allowed.")

if data.get("relay_domain"):
    raise SignUpError("Please use your real email address to register.")

normalized_email = data.get("normalized_email", email)

# Proceed with signup

After: Gate decision

response = requests.post(
    f"https://api.usercheck.com/v0/gates/{GATE_ID}/decisions",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={"email": email},
)
data = response.json()
decision = data.get("decision", {})

if decision.get("action") == "block":
    message = decision.get("matched_rule", {}).get("message")
    raise SignUpError(message)

if decision.get("action") == "challenge":
    tagAccountAsHighRisk()

normalized_email = data.get("signals", {}).get("email", {}).get("normalized", email)

# Proceed with signup

5. Using rule messages in your UI

Each decision includes an optional matched_rule.message field when a rule triggers.
If you want to display context to your users, you can surface this message in your own interface.

Typical usage:

  1. Inspect decision.action (allow, block, or challenge)
  2. Optionally read decision.matched_rule.message for user-facing context

How you handle that information is entirely up to your application.

6. Need help?

For complex migrations or multi-condition logic, contact [email protected] and we’ll walk through your setup.

Previous
Decision Endpoint