> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abstractapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send a check

> Risk API reference for the check endpoint: request fields, response fields, test fixtures and errors.

Evaluates one signup or login against the policy for its flow and returns a recommendation. Call it from your backend with a Secret key. The server SDKs build this request for you; use the HTTP API directly only if there is no SDK for your stack.

```http theme={null}
POST https://protection-api-service.vercel.app/v1/protection
Authorization: Bearer sk_...
Content-Type: application/json
```

> [!WARNING]
>
> **Draft value.** The Risk API address and check path are placeholders until the final public address is set.

```bash cURL theme={null}
curl -X POST 'https://protection-api-service.vercel.app/v1/protection' \
  -H 'Authorization: Bearer sk_...' \
  -H 'Content-Type: application/json' \
  -d '{
    "flow": "signup",
    "event_id": "signup:user_123",
    "email": "person@example.com",
    "device_token": "dtok_...",
    "client": {
      "ip": "203.0.113.10",
      "user_agent": "Mozilla/5.0 ...",
      "accept_language": "en-US,en;q=0.9",
      "ip_source": "explicit",
      "ip_trusted": true
    },
    "context": { "surface": "password_signup" }
  }'
```

```json 200 theme={null}
{
  "contract_version": "1",
  "flow": "signup",
  "recommendation": "review",
  "check_id": "chk_123",
  "event_id": "signup:user_123",
  "policy": {
    "id": "signup_protection",
    "version": 4,
    "configured": true,
    "action": "review",
    "reasons": [{ "code": "R3", "label": "Disposable email" }]
  },
  "data_quality": {
    "confidence": "verified",
    "gaps": []
  },
  "diagnostics": {
    "device": { "token_present": true, "token_valid": true, "reason": null },
    "ip_source": "explicit",
    "ip_trusted": true,
    "velocity": {
      "status": "none",
      "contributors": [],
      "reason": "No velocity detector reached a monitoring threshold."
    }
  },
  "reasons": [
    { "rule": "R3", "label": "Disposable email", "expr": "email.is_disposable = true", "contribution": "matched -> review" }
  ]
}
```

## Request body

Send at least one of `email`, `phone`, `client.ip` or `device_token`.

**flow** `string` *required*

The business flow: `signup` or `login`. The Risk Platform runs the policy mapped to this flow.

**event\_id** `string`

Your correlation key for this check, up to 128 characters. Generate it on your server. A retry with the same event ID and the same inputs returns the existing check; the same event ID with different inputs returns `409 event_conflict`. Strongly recommended.

**email** `string`

The email address used in the signup or login.

**phone** `string`

The phone number, when your flow collects one.

**device\_token** `string`

The device token from the `x-abstract-device-token` header of the browser request. Opaque and single-use; don't parse it. See [Device tokens](https://docs.abstractapi.com/api/risk-platform/device-tokens.md).

**client** `object`

The original browser context, read from the user's request to your server.

**properties**

**ip** `string`

The original client IP address. This is the IP signal for the check.

**user\_agent** `string`

The original browser user agent.

**accept\_language** `string`

The original `Accept-Language` header.

**ip\_source** `string`

Where you got the IP: `explicit`, `platform`, `proxy_header`, `socket` or `unavailable`.

**ip\_trusted** `boolean`

Whether you trust that source. A forwarded header you haven't validated is untrusted.

**context** `object`

Small, non-sensitive metadata of your own, such as the signup surface. Never put passwords, cookies, session data or authorization headers here.

**test\_mode** `object`

Returns a fixed test response instead of running a live check. Test checks aren't stored, and test responses carry the `X-Protection-Test-Mode: true` header.

**properties**

**fixture** `string` *required*

`allow`, `review`, `block`, `device_invalid` or `timeout`.

**delay\_ms** `integer`

Delay for the `timeout` fixture, from 1 to 5000 milliseconds.

## Response

**contract\_version** `string`

Response contract version. Currently `"1"`.

**flow** `string`

The flow you sent.

**recommendation** `string | null`

`allow`, `review` or `block`. `null` when no policy is configured for the flow.

**check\_id** `string`

The unique ID of this check. Use it to find the check in the dashboard and to report outcomes.

**event\_id** `string`

The event ID you sent.

**policy** `object`

The policy that scored the check.

**properties**

**id** `string | null`

Policy ID. `null` when no policy is configured.

**version** `integer | null`

The policy version that scored the check.

**configured** `boolean`

`false` when the flow has no policy yet.

**action** `string | null`

Same value as `recommendation`.

**reasons** `array`

The rules behind the recommendation. Each has a stable `code` (the rule ID) and an optional display `label`.

**data\_quality** `object`

How complete the evidence was: `confidence` (`verified`, `partial` or `unverifiable`) and `gaps`, the fields a rule needed but couldn't resolve.

**diagnostics** `object`

Request quality: `device` (`token_present`, `token_valid`, `reason`), `ip_source`, `ip_trusted`, and the `velocity` assessment (`status` of `none`, `watch` or `high`, `contributors`, `reason`).

**reasons** `array`

The rule trace: for each rule, `rule`, `label`, `expr` (the condition as text) and `contribution`.

**email** `object`

The email signal used by the check, from [Email Reputation](https://docs.abstractapi.com/api/email-reputation.md).

**phone** `object`

The phone signal used by the check, from [Phone Intelligence](https://docs.abstractapi.com/api/phone-intelligence.md).

**ip** `object`

The IP signal used by the check, from [IP Intelligence](https://docs.abstractapi.com/api/ip-intelligence).

**device** `object`

The device evidence from the device token: browser, automation and integrity flags.

**context** `object`

The context the check was evaluated with.

### Compatibility fields

Responses also include `call_id`, `run_id`, `verdict`, `risk_level`, `decision_phase`, `score`, `policy_applied`, `policy_version`, `data_gaps` and `check_confidence`. They are kept for older integrations and are deprecated. Use `check_id`, `recommendation`, `policy` and `data_quality` instead.

## Errors

| Status | `error` | Common `reason` | What to do |
| - | - | - | - |
| 400 | `bad_request` | `malformed_json` | Fix the request body. Send at least one signal. |
| 401 | `unauthorized` | `unauthorized` | Check the Secret key. |
| 403 | `forbidden` | `sandbox_fixture_required` | The public test key only works with `test_mode.fixture`. |
| 409 | `conflict` | `event_conflict` | The event ID was reused with different inputs, or is still processing. Use a new event ID for a new action. |
| 429 | `rate_limited` | | Back off and retry after `Retry-After`. |
| 429 | `rate_limited` | `unconfigured_flow_limit_exceeded` | The flow has no policy and reached its limit. Create a policy for it. See [Flows without a policy](https://docs.abstractapi.com/api/risk-platform/policies.md#flows-without-a-policy). |
| 500 | `internal_error` | | Retry only with the same event ID. |
| 503 | `service_unavailable` | | Continue your flow as allow. |

See [Errors](https://docs.abstractapi.com/api/risk-platform/api-reference/errors.md) for the error format.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.