# Response fields

> Every field in a /v1/check response: category, recommendation, confidence, flags, mail, workspace, integrations, reasons, degraded and more.

Source: https://isbusinessemail.com/docs/response-fields

This is the full response for a secret key. [Publishable keys](https://isbusinessemail.com/docs/authentication#publishable-keys) get a reduced subset.

```json
{ "email": "jane+news@acme.io", "normalized_email": "jane@acme.io", "domain": "acme.io",
  "is_business": true, "category": "business", "confidence": 0.96, "recommendation": "allow",
  "is_free_provider": false, "is_disposable": false, "is_relay": false, "is_role_account": false,
  "shared_inbox": { "confidence": 0, "match": null }, "group": { "confidence": 0, "match": null },
  "is_blocked": false, "is_new_domain": false, "is_lookalike": false, "has_subaddress": true, "did_you_mean": null,
  "mail": { "has_mx": true, "provider": "google_workspace", "mx": [{ "priority": 1, "host": "smtp.google.com" }],
            "spf": "v=spf1 include:_spf.google.com ~all", "dmarc_policy": "reject" },
  "workspace": { "google_workspace": { "detected": true, "evidence": ["mx_google","dkim_google"] },
                 "microsoft_365": { "detected": false, "tenant_id": null, "auth": null, "identity_provider": null, "evidence": [] },
                 "other_suite": null, "pending": false },
  "integrations": { "google_workspace_ready": true, "microsoft_365_ready": false },
  "domain_age_days": null, "reasons": ["mx_google_workspace","dmarc_reject","txt_saas_tokens:3"],
  "degraded": false, "cached": false, "took_ms": 38, "request_id": "req_…" }
```

## Input and identity

| Field | Type | Meaning |
|---|---|---|
| `email` | string \| null | The address you sent, trimmed. `null` for domain and URL checks. |
| `url` | string | Only for URL checks: the website address you sent. Its host (without `www.`) is `domain`. |
| `normalized_email` | string \| null | Lowercased, Unicode-normalized, IDN domain in punycode, `+tag` removed. Use it to de-duplicate signups. `null` for domain checks. |
| `domain` | string | The domain part, normalized. Lookups use its registrable domain (`mail.acme.co.uk` → `acme.co.uk`). |

## Verdict

| Field | Type | Meaning |
|---|---|---|
| `category` | string | One of `business`, `personal`, `disposable`, `relay`, `education`, `government`, `invalid`, `unknown`. See [Categories and policies](https://isbusinessemail.com/docs/categories-and-policies). |
| `is_business` | boolean | `true` for `business`, `education` and `government`. The simple yes/no. |
| `recommendation` | string | `allow`, `review` or `block`, for the policy you requested (`b2b` by default). |
| `confidence` | number | 0 to 1. How sure the engine is about `category`. List matches are near 1; custom domains are scored from DNS signals. Below a threshold the category becomes `unknown`. |
| `reasons` | string[] | Machine-readable reason codes, strongest first. Some carry a count suffix, e.g. `txt_saas_tokens:3`. See [Reason codes](https://isbusinessemail.com/docs/reason-codes). |

## Flags

| Field | Type | `true` when… |
|---|---|---|
| `is_free_provider` | boolean | The domain is a shared-domain provider: one domain, many unrelated people (gmail.com, outlook.com, yahoo.com, gmx.de, icloud.com, ISP domains…). Paid consumer services count too: "free" means "not the company's own domain". |
| `is_disposable` | boolean | Throwaway inbox service, or a domain whose mail servers serve known disposable domains |
| `is_relay` | boolean | Privacy relay that forwards to a hidden inbox (Apple Hide My Email, Firefox Relay, DuckDuckGo, SimpleLogin, addy.io) |
| `is_role_account` | boolean | The local part is a role, not a person: `info@`, `sales@`, `support@`, `noreply@`… |
| `shared_inbox` | object | Hint that the address is a shared inbox: one mailbox several people answer from (a Microsoft 365 shared mailbox, a Google collaborative inbox, a helpdesk address) such as `support@`, `billing@` or `sales-eu@`. `confidence` is `0.3` (low) on a name match and `0` otherwise; `match` is the word that matched. See [shared inboxes and groups](#shared-inboxes-and-groups). |
| `group` | object | Hint that the address is a group that forwards to many members (a Google Group, a Microsoft 365 group or distribution list) such as `team@`, `all@` or `berlin-team@`. `0.3` (low) on a name match, `1` for `@googlegroups.com`, `0` otherwise. Neither hint changes `recommendation`. |
| `is_blocked` | boolean | The domain, or (for secret keys) the exact address, is on our blocklist built from spam and abuse reports |
| `is_new_domain` | boolean | Registered less than 30 days ago. Only known with `deep=true` or when we have already enriched the domain. |
| `is_lookalike` | boolean | The domain imitates a popular provider with confusable characters or punycode |
| `has_subaddress` | boolean | The address has a `+tag` (`jane+news@`) |
| `did_you_mean` | string \| null | A suggested correction when the domain looks like a typo of a popular provider (for example, for `gmial.com`). Show it to the user; don't silently replace their input. |

## `mail`

| Field | Type | Meaning |
|---|---|---|
| `mail.has_mx` | boolean | The domain can receive mail (MX records, not a null MX) |
| `mail.provider` | string \| null | Short identifier of who hosts the mailboxes, from MX and other DNS records, e.g. `google_workspace`. Treat it as an open set; new values can appear. `null` when unknown. |
| `mail.mx` | array | MX records, `{priority, host}`, lowest priority first |
| `mail.spf` | string \| null | The domain's SPF record, or `null` if it publishes none |
| `mail.dmarc_policy` | string \| null | Published DMARC policy: `reject`, `quarantine`, `none`, or `null` if there's no DMARC record |

## `workspace`

Detection runs per company domain. Details in [Workspace detection](https://isbusinessemail.com/docs/workspace-detection).

| Field | Type | Meaning |
|---|---|---|
| `workspace.google_workspace.detected` | boolean | The domain's mail or DNS shows Google Workspace |
| `workspace.google_workspace.evidence` | string[] | Short evidence tags, e.g. `mx_google`, `dkim_google` |
| `workspace.microsoft_365.detected` | boolean | The domain belongs to a Microsoft Entra ID tenant (Microsoft 365) |
| `workspace.microsoft_365.tenant_id` | string \| null | The tenant's GUID, from Microsoft's public OpenID discovery document |
| `workspace.microsoft_365.tenant_region` | string \| null | Tenant region scope reported by Microsoft (e.g. `EU`, `NA`, `WW`), when detected |
| `workspace.microsoft_365.auth` | string \| null | `managed` (passwords in Entra ID) or `federated` (sign-in redirected to another identity provider) |
| `workspace.microsoft_365.identity_provider` | string \| null | For federated tenants, the identity provider we recognized (Okta, ADFS, Ping…) |
| `workspace.microsoft_365.evidence` | string[] | Evidence tags for the Microsoft detection |
| `workspace.other_suite` | string \| null | Another hosted suite seen in MX: Zoho, Proton, Fastmail, Yandex 360… `null` if none |
| `workspace.pending` | boolean | `true` when the Microsoft tenant lookup didn't finish within its 0.7 s budget and continues in the background. Check again later for the full result. |

Google Workspace and Microsoft 365 can **both** be `true`: a company might sign in with Entra ID but keep mail on Google, or be mid-migration.

## `integrations`

| Field | Type | Meaning |
|---|---|---|
| `integrations.google_workspace_ready` | boolean | The company has a Google Workspace tenant, so admin-level Google integrations (Admin SDK, domain-wide delegation, Shared Drives) are possible |
| `integrations.microsoft_365_ready` | boolean | The company has a Microsoft 365 / Entra ID tenant, so Graph admin consent, SharePoint, OneDrive for Business and Teams integrations are possible |

"Ready" means the tenant exists. It doesn't mean this person is an admin, or that their admin will consent.

## Enrichment

| Field | Type | Meaning |
|---|---|---|
| `domain_age_days` | number \| null | Days since the domain was registered, from RDAP. Filled with `deep=true` (or when we already have it); otherwise `null`. |

## Operational

| Field | Type | Meaning |
|---|---|---|
| `degraded` | boolean | DNS lookups failed or timed out; the answer comes from our lists only and `confidence` is lower. Consider treating `review` as `allow` and re-checking later. |
| `cached` | boolean | Served from cache |
| `took_ms` | number | Server-side processing time in milliseconds |
| `request_id` | string | Unique ID for this request. Include it when you contact support. |

## Reduced response (publishable keys)

Publishable keys receive `category`, `is_business`, `recommendation`, `confidence`, `did_you_mean`, the top reasons and `workspace.google_workspace` / `workspace.microsoft_365` as detected-or-not. They never receive `is_blocked`, `mail`, tenant details or deep enrichment.

## Compatibility

Within `/v1` we only make additive changes: new fields, new `reasons` codes, new `mail.provider` and `other_suite` values. Ignore fields you don't know and treat unknown reason codes as informational. See [Versioning and deprecation](https://isbusinessemail.com/docs/changelog-policy).

## Shared inboxes and groups

Two kinds of address are read by more than one person, and they behave differently:

- A **shared inbox** is one mailbox several people answer from: a Microsoft 365 shared mailbox, a Google collaborative inbox, a helpdesk address. Typical names: `support@`, `info@`, `billing@`, `orders@`.
- A **group** forwards each message to many members: a Google Group, a Microsoft 365 group or a distribution list. Typical names: `team@`, `all@`, `everyone@`, `engineering@`.

On a company's own domain both have exactly the same DNS and mail servers as a person's mailbox. The only way to know for sure would be to ask Google or Microsoft about that address, which is account probing, and we never do it. So each hint uses the one piece of evidence there is, the name, and has its own confidence:

| `confidence` | When | Examples |
|---|---|---|
| `1` | `group` only: the domain is `googlegroups.com`, where every address is a Google Group | `book-club@googlegroups.com` |
| `0.3` (low) | The local part is, starts with or ends with a word from that hint's list | shared inbox: `support@`, `support2@`, `eu.support@`; group: `team@`, `berlin-team@`, `all-staff@` |
| `0` | No sign, or not a custom domain | `jane.doe@`, anything at `gmail.com` |

Some names are commonly either, such as `sales@` and `projects@`; they get a low score on both. Plenty of people own a mailbox called `projects@` or `sales@`, so treat a low match as a hint: route it to a team queue or ask for a named contact, but don't block on it. Role names such as `info@` and `support@` also set `is_role_account`, which is what the `b2b` and `strict` policies act on.
