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

# Understanding the Response

> Interpret Signup Risk API decisions, checks, explanations, assessment context, and metadata.

Every successful analysis returns a JSON object with up to five top-level sections. Two are request-controlled: `checks` and `explanation` are only present when you ask for them.

| Key           | Present                                             | Contents                                                           |
| ------------- | --------------------------------------------------- | ------------------------------------------------------------------ |
| `email`       | always                                              | Normalized address, structural validity, canonical identity form   |
| `decision`    | always                                              | Recommended action, risk score, risk band, summary, and assessment |
| `checks`      | only when requested (`options.include_checks`)      | Per-check verdicts, evidence, and score contributions              |
| `explanation` | only when requested (`options.include_explanation`) | Plain-language reasons behind the decision                         |
| `metadata`    | always                                              | Warnings, usage and quota snapshot, plan context                   |

Optional sections are **omitted** from the response when not requested — they are never `null` in a single analysis response.

```json theme={null}
{
  "email": {
    "input": "maria.garcia@protonmail.com",
    "normalized": "maria.garcia@protonmail.com",
    "normalized_preserving_case": "maria.garcia@protonmail.com",
    "canonical": "maria.garcia@protonmail.com",
    "is_well_formed": true,
    "format_issues": [],
    "format_explanation": "The email address is structurally well formed. This does not mean it is safe, trusted, deliverable, or non-disposable.",
    "is_internationalized": false
  },
  "decision": {
    "action": "allow",
    "risk_score": 5,
    "risk_band": "low",
    "summary": "Low-risk signup. No significant risk checks failed.",
    "assessment": {
      "confidence": "high",
      "evidence_strength": "moderate",
      "evidence_coverage": "broad",
      "uncertainty": "low",
      "limitations": []
    }
  },
  "metadata": {
    "warnings": [],
    "usage": {
      "requests": { "used": 1, "limit": 10000, "unlimited": false, "remaining": 9999 },
      "explanations": { "used": 0, "limit": 500, "unlimited": false, "remaining": 500 }
    },
    "plan": {
      "current_plan": "Developer",
      "billing_period": { "starts": "2026-09-16T00:00:00Z", "ends": "2026-10-16T00:00:00Z" },
      "reset_at": "2026-10-16T00:00:00Z"
    },
    "assessment_version": "2026.08.28"
  }
}
```

The example above is illustrative — score values depend on current check data, and `metadata.usage` and `metadata.plan` reflect your own account. For exact field definitions, see the [API reference](/api-reference).

## `email`

The `email` section reports how the address was normalized and structurally interpreted:

| Field                        | Meaning                                                                                                                                                                                                                                                                   |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `input`                      | The address exactly as submitted                                                                                                                                                                                                                                          |
| `normalized`                 | Lowercased, Unicode-normalized, punycode-domain form. Use for deduplication and cache keys                                                                                                                                                                                |
| `normalized_preserving_case` | Same normalization, but the local part keeps its submitted case. For display only — never deduplicate on it                                                                                                                                                               |
| `canonical`                  | Identity form used to group addresses that belong to the same mailbox provider identity (for example, folding `googlemail.com` to `gmail.com` and stripping dot/plus-addressing where the provider ignores it). Useful for per-identity decisions; not a delivery address |
| `is_well_formed`             | Whether the address is structurally valid. Always `true` in a successful response — invalid input is rejected with a `400` before scoring                                                                                                                                 |
| `format_issues`              | List of structural problems. Always empty in a successful response                                                                                                                                                                                                        |
| `format_explanation`         | Plain-language description of the structural verdict                                                                                                                                                                                                                      |
| `is_internationalized`       | Whether the local part contains non-ASCII characters (internationalized/EAI addresses)                                                                                                                                                                                    |

<Note>
  Structural validity is not mailbox verification. Signup Risk API does not
  confirm mailbox existence, SMTP deliverability, or catch-all behavior — it
  analyzes the address, its domain, and the context you supply.
</Note>

## `decision`

The `decision` section is the part your integration acts on:

| Field        | Meaning                                                               |
| ------------ | --------------------------------------------------------------------- |
| `risk_score` | Integer from 0 to 100; higher means more signup risk                  |
| `risk_band`  | `low`, `moderate`, `high`, or `very_high`                             |
| `action`     | Recommended action: `allow`, `review`, or `block`                     |
| `summary`    | One-line, deterministic description of the decision                   |
| `assessment` | How strongly the available evidence supports the decision (see below) |

The band is derived directly from the score, and the action from the band:

| Risk score | Risk band   | Recommended action |
| ---------- | ----------- | ------------------ |
| 0–24       | `low`       | `allow`            |
| 25–49      | `moderate`  | `review`           |
| 50–74      | `high`      | `review`           |
| 75–100     | `very_high` | `block`            |

`action` is a **recommendation**. Signup Risk API never allows or blocks anyone itself — your application remains responsible for enforcement and should apply its own policy on top of the score. The score estimates signup risk given the available evidence; it is not a judgment that a person is trusted or that fraud has been proven.

## `decision.assessment`

The assessment describes the quality of the evidence behind the decision:

| Field               | Values                            | Meaning                                                           |
| ------------------- | --------------------------------- | ----------------------------------------------------------------- |
| `confidence`        | `high` \| `medium` \| `low`       | How stable the recommended action is given the available evidence |
| `evidence_strength` | `strong` \| `moderate` \| `weak`  | How authoritative the evidence that drove the decision is         |
| `evidence_coverage` | `broad` \| `partial` \| `limited` | How much of the relevant evidence could actually be evaluated     |
| `uncertainty`       | `low` \| `moderate` \| `high`     | How much unresolved doubt remains after reconciling all checks    |
| `limitations`       | array of codes                    | Response-specific caveats, at most five, ordered by severity      |

The distinction matters: the **risk score** estimates signup risk; the **assessment** tells you how strongly the available evidence supports that estimate. A high score with low confidence deserves different handling than a high score with high confidence.

`confidence` is a qualitative stability rating, not a probability. When evidence was unavailable — for example a temporary DNS failure, a missing name, or an IP not supplied — the assessment reflects it:

* `evidence_coverage` drops to `partial` or `limited`
* `uncertainty` rises
* a code such as `domain_intelligence_unavailable`, `name_not_supplied`, or `ip_not_supplied` appears in `limitations`

## `checks`

Request per-check detail with `options.include_checks`:

```json theme={null}
{
  "email": "maria.garcia@protonmail.com",
  "options": {
    "include_checks": true
  }
}
```

Checks provide the structured, machine-readable evidence used by the scoring engine. When enabled, all eight checks are present — plan gating degrades a check's content (for example, `ip_reputation` reports `available: false`) rather than removing it.

Most checks share a common shape:

| Field               | Meaning                                                  |
| ------------------- | -------------------------------------------------------- |
| `result`            | The check's verdict, from a check-specific set of values |
| `confidence`        | How strongly the check supports its own result           |
| `method`            | How the result was determined                            |
| `evidence`          | Itemized supporting evidence with per-item descriptions  |
| `risk_contribution` | How much this check added to the overall `risk_score`    |

Each check adds its own fields on top of this common shape. For example, `disposable_email` adds `is_disposable`; `ip_reputation` adds `network` classification and an `available` flag. When evidence for a check could not be evaluated, its `result` is `unknown`, `confidence` is `unknown`, and its `risk_contribution` is `0` — unavailable evidence is never treated as either a pass or a failure.

The illustrative snippet below shows the shape of `checks.disposable_email` for a clean address:

```json theme={null}
{
  "result": "none",
  "confidence": "high",
  "method": "dataset_exact",
  "evidence": [],
  "risk_contribution": 0,
  "is_disposable": false
}
```

See [Core Concepts](/core-concepts) for what each of the eight checks evaluates, and the [API reference](/api-reference) for their exact schemas.

## `explanation`

Request a human-readable decision narrative with `options.include_explanation`:

```json theme={null}
{
  "email": "maria.garcia@protonmail.com",
  "options": {
    "include_checks": true,
    "include_explanation": true
  }
}
```

The distinction between the two sections:

* `checks` — structured, machine-readable evidence for your own rules, logging, and auditing
* `explanation` — human-readable decision context: a summary, the top contributing reasons, grouped risk factors, and the reasoning behind the recommendation

Explanations draw on a separate monthly allowance. When the allowance is exhausted, the analysis still succeeds — `explanation.explanation_available` is `false` with `explanation_omitted_reason: "limit_exceeded"`, the `X-Explanation-Omitted: true` header is set, and a warning appears in `metadata.warnings`. See [Warnings & Quotas](/warnings-and-quotas).

## `metadata`

`metadata` carries context about the request and your account:

| Field                 | Meaning                                                                                                                                 |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `warnings`            | Non-fatal notices (always an array; empty when there are none). See [Warnings & Quotas](/warnings-and-quotas)                           |
| `usage.requests`      | Monthly request usage: `used`, `limit` (`null` when unlimited), `unlimited`, `remaining`                                                |
| `usage.explanations`  | Monthly explanation allowance usage, same shape                                                                                         |
| `plan.current_plan`   | Your current plan                                                                                                                       |
| `plan.billing_period` | Current billing period start and end                                                                                                    |
| `plan.reset_at`       | When your monthly usage window resets                                                                                                   |
| `assessment_version`  | Version of the assessment logic that produced `decision.assessment`                                                                     |
| `cache`               | Present only when the result was served from the server-side cache: `hit`, `age_seconds`, and the `scoring_version` of the cached entry |

The response shape varies slightly across operations: batch responses wrap per-address results in a `results` array (inapplicable sections are `null` per item rather than omitted), bulk jobs return a CSV with the core decision columns, and webhook payloads carry a reduced decision-first envelope. See the [API reference](/api-reference) for each operation's schema.

## Next steps

<Card title="Core Concepts" icon="graduation-cap" href="/core-concepts">
  How scoring works: determinism, the eight checks, industry profiles, and evidence reconciliation.
</Card>

<Card title="API reference" icon="square-code" href="/api-reference">
  Exact request and response schemas for every operation.
</Card>
