Gates
Decision endpoint
Use the Decision endpoint to evaluate a gate in real time. It is the only Gates endpoint that consumes credits.
Endpoint
POST /v1/gates/{gate_id}/decisions
gate_id is the id shown in the dashboard, and returned by the Management API. The key must belong to the gate's environment; a gate in another one returns 404 gate_not_found.
Authentication
Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Call the endpoint from your backend, never from the browser. The key is secret, and the endpoint does not send CORS headers, so browsers block the call anyway.
Request body
Send a JSON object with Content-Type: application/json. A form-encoded or multipart body returns 400 invalid_json.
curl -X POST "https://api.usercheck.com/v1/gates/01k2wjgq8rnv6t0aefy3s7xdhb/decisions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'
Send either email or domain, not both. A request carrying neither returns 422 missing_input, and one carrying both returns 422 both_email_and_domain_provided. Leave out the field you don't use: sending email or domain as null or an empty string returns 422 validation_failed.
{
"email": "[email protected]",
"ip": "1.1.1.1" // optional
}
or
{
"domain": "github.com",
"ip": "1.1.1.1" // optional
}
ip is optional. It adds IP intelligence to the signals and costs 2 extra credits. Send a single IPv4 or IPv6 address, without a port, CIDR prefix, or forwarded-address list. A malformed value returns 422 invalid_ip before a decision is made or credits are charged. Omitting ip or sending null, an empty string, or whitespace treats it as absent: no signals.ip and no extra credits.
Example response
The decision comes back as a flat object: the verdict at the top, the evidence under it.
{
"id": "01k1skm0zdceees5qa9n3m5epx",
"gate_id": "01k2wjgq8rnv6t0aefy3s7xdhb",
"action": "allow",
"rule": {
"id": "01k1hxqrn2f7xfreq20y0p012d",
"name": "Allow professional email providers",
"message": null
},
"input": {
"email": "[email protected]",
"ip": "1.1.1.1"
},
"signals": {
"email": {
"address": "[email protected]",
"normalized": "[email protected]",
"domain": "github.com",
"local_part": "octocat",
"subaddress": null,
"disposable": false,
"role_account": false
},
"domain": {
"name": "github.com",
"authority": 96,
"tld_trust": 1,
"tld": "com",
"sld": "github",
"subdomain": null,
"age_days": 6871,
"mx": true,
"mx_records": [
{ "hostname": "github-com.mail.protection.outlook.com", "priority": 0 }
],
"mx_providers": [
{ "slug": "microsoft", "type": "mailbox", "grade": "professional" }
],
"spf": "relaxed",
"dmarc": "quarantine",
"disposable": false,
"public_domain": false,
"relay_domain": false,
"free_subdomain": false,
"spam": false,
"blocklisted": false
},
"ip": {
"address": "1.1.1.1",
"abuse": {
"detected": false
},
"anonymity": {
"proxy": {
"detected": false
},
"relay": {
"detected": false
},
"tor": {
"detected": false
},
"vpn": {
"detected": false
}
},
"geo": {
"city": "Hong Kong",
"country": "Hong Kong",
"country_code": "HK",
"continent": "Asia",
"continent_code": "AS"
},
"hosting": {
"detected": true
},
"network": {
"asn": 13335,
"aso": "Cloudflare, Inc.",
"domain": "cloudflare.com",
"type": "hosting"
}
}
},
"duration_ms": 52.62,
"created_at": "2026-08-18T03:57:18+00:00"
}
actionis the verdict:allow,block, orchallenge.ruleis the rule that decided it, including its optional user-facingmessage. It isnullwhen no rule matched and the gate'sdefault_actionapplied.signalsholds the email, domain, and IP intelligence the rules were evaluated against.signals.emailis only present when the request sent anemail, andsignals.iponly when it sent a validip. Some fields only appear when they apply, such asdomain.disposable_provider, and some arenullwhen the data is unknown, such asdomain.age_days. Rules & Conditions lists every field.ididentifies the decision. It is also its handle in the decision log, so you can read the decision back later with the Management API.
Which rule produced action, and what happens when several match, is covered in Rules & Conditions.
Error responses
Errors return the matching HTTP status code and a JSON body with a stable error code and a human-readable message:
{
"error": "gate_not_found",
"message": "Gate not found."
}
Codes specific to this endpoint:
404 gate_not_found: Unknowngate_id, or a gate outside the key's environment422 missing_input: Neitheremailnordomainprovided422 both_email_and_domain_provided: Bothemailanddomainwere provided422 invalid_email: The email format or its domain is invalid422 invalid_domain: The domain format or suffix is invalid422 invalid_ip: The IP address format is invalid
If an address or domain is well formed but its suffix is not a public top-level domain (such as .test, .internal, or .corp), the code is still invalid_email or invalid_domain, and the message reads "Domain has an unknown or reserved top-level domain".
It can also return the codes every Gates endpoint shares, including:
400 invalid_json: The body is not JSON, or is sent withoutContent-Type: application/json401 unauthorized: The API key is missing or not valid. After 5 such requests in an hour from one IP, the API answers429 rate_limit_exceededinstead403 pro_only: The account is not on a plan that includes Gates422 validation_failed:emailordomainis empty,null, not a string, or longer than 255 characters429 rate_limit_exceeded: Too many requests, see Rate limits429 quota_exceeded: The monthly credits are used up
An error response uses no credits. Errors lists every code and how to handle each one.
Rate limits
Decisions share your account's per-second rate limit with the data API (/domain and /email) and with the keys of every environment. Management API requests have a separate limit of their own.
Timeouts and failures
Decisions usually return in well under a second. A domain whose DNS does not respond can take several seconds.
- Set a client timeout of 3 to 5 seconds.
- Decide ahead of time what your signup does when the call fails or times out. Most apps allow the signup and log the failure, so a problem on our side never blocks real users.
- Don't retry inside the user's request. Apply your fallback and move on.
Errors covers which responses are safe to retry.
The /v0 endpoint
Integrations built during the beta call POST /v0/gates/{gate_id}/decisions. It keeps working, with its original response and error format. New integrations should use /v1. Migrate from v0 to v1 lists every difference.