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 → blockif 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, orchallenge) - matched_rule — which rule triggered, including its name and optional message
- signals — the same diagnostic data you’d get from
/emailor/domain
The Gate already applies your rules and returns a verdict. Treat
signalsas 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:
- Inspect
decision.action(allow,block, orchallenge) - Optionally read
decision.matched_rule.messagefor 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.