Gates
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 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:
- block when
disposableistrue - block when
spamistrue
Then recreate it as rules inside your gate. Each rule checks one or more fields (like domain.mx or email.role_account) and chooses an action: allow, block, or challenge. See Rules & Conditions for the fields a condition can use.
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/v1/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 puts the verdict at the top. Shortened here to the fields this migration cares about:
{
"action": "block",
"rule": { "name": "Block domains with no MX records", "message": null },
"signals": {
"email": { "disposable": false },
"domain": { "mx": false }
}
}
- action: the gate's decision (
allow,block, orchallenge) - rule: which rule decided it, including its name and optional message;
nullwhen the gate's default action applied - signals: the same intelligence you would get from
/emailor/domain
The full response shape is documented on the Decision Endpoint page.
Note
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/v1/gates/{GATE_ID}/decisions",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={"email": email},
)
data = response.json()
if data.get("action") == "block":
message = (data.get("rule") or {}).get("message")
raise SignUpError(message)
if data.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 rule.message field when a rule matched. If you want to show context to your users, surface this message in your own interface.
Typical usage:
- Inspect
action(allow,block, orchallenge) - Optionally read
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].