Skip to main content
An assessment records what NoResponse knew at one time. An account holds the current decision. An outcome records what your team later learned. An enforcement records what your platform did. Keep these records separate. Blocking a user is an action, not proof of abuse.

Report an outcome

Send an account report with your assess key and a stable Idempotency-Key:
Report account abuse
The response is a receipt that does not change. It records the report id, observation time, receipt time and actor. It also names the effective report and the account versions before and after the write. A retry with the same key and body returns that receipt. Reusing the key with different content returns idempotency_key_reused. An abuse report adds one account-level reason in this environment. It does not change earlier assessments or affect another workspace’s accounts. A flow decision change sends account.risk_changed. Apply the event with the highest account risk_version. Use changed-account polling to recover missed deliveries. The existing POST /v1/assessments/{assessment_id}/outcomes operation keeps its behavior. Its identifier marks are separate from account feedback. Correct a report through the operation that recorded it.

Correct or retract a report

Get GET /v1/accounts/{account_id}/outcomes with a history key. The page’s effective_outcome_id names the current report. Each receipt keeps its original effective report and risk version. A correction names the current report in supersedes:
Correct a report
Use a new idempotency key. A stale correction returns outcome_conflict rather than replacing a newer report. legitimate and false_positive clear the account feedback reason. Other evidence can still require review or blocking. unknown alone records uncertainty without changing the current report. unknown with supersedes retracts that report. Reports expire under the environment’s retention. Maintenance clears an expired report’s reason and advances the account version. An account read also resolves an expired reason before returning the current decision. Historical decisions keep the reason that applied at their version.

Find accounts and assessments by a submitted identifier

Select an email, phone number or username in an account or assessment to open the corresponding search. The console keeps the workspace, environment, match mode and return path. Results come from bounded server queries. The two search routes accept the same identifier object:
Identifier filter
Use POST /v1/accounts/search for distinct accounts. An account matches when any retained admitted assessment submitted the identifier, even when its latest assessment sent a different value. Use POST /v1/assessments/search for the individual assessments that sent it. Add the required from and to range. Its decisions are assessment decisions, separate from current account risk.

Combine submitted identifiers

Use identifier_expression to combine email, phone and customer username terms with and and or. Each term uses the match rules below. Choose the scope explicitly: Suppose an account submitted an email yesterday and a phone today. An AND search with scope: "account" can find it. The same search with scope: "assessment" requires both identifiers in one submission. Neither mode combines identifiers from different accounts. This example finds one submission with the phone and either email:
Phone with either submitted email
Send it to POST /v1/accounts/search for distinct accounts. For assessment results, use POST /v1/assessments/search and add from and to. That range applies to the returned submissions. Change the scope to account to search across an account’s retained history. Account scope has no time filter. Effective retention still limits each term’s matching submissions. Assessment search rejects account scope with 400 invalid_request. In the console, Submitted together and Across account history express these scopes. Assessment filters use Submitted together. Account filters offer both choices. AND requires every child. OR requires at least one child.

Expression limits and duplicate terms

Each node contains exactly one member: term, and or or. A term contains the existing identifier shape. A group has 2 to 8 children. The expression allows at most three nested group levels and eight term occurrences in total. A single root term is allowed. Repeated terms count toward the eight-term limit. Terms with the same kind, match rule, namespace and normalized comparison have one effect and one matching record. Different match rules remain distinct. Duplicates do not require separate submissions. Empty groups, unknown members, unsupported scopes and expressions beyond these limits return 400 invalid_request. Choose one filter: identifier_expression, identifier or legacy email. POST /v1/accounts/search also takes email_domain, as a fourth choice. It finds the accounts that sent an email of the domain or its subdomains, as an email_domain list entry matches them. Other filters combine with the chosen filter using AND. The current permissions and submitted-only boundary apply to every term. Source discoveries cannot complete a combination.

Read the matching submissions

Expression results include matched_identifiers instead of matched_identifier. Each entry preserves the original submitted value and its assessment_id. It also carries kind, match_basis, provenance: "submitted" and the username namespace when needed. term_index identifies a term’s first position in the request, starting at zero. Count leaves in depth-first order, visiting children in their listed order. The example above numbers the phone 0 and the emails 1 and 2. The response lists each satisfied unique term in that order. It includes satisfied terms from OR branches even when another branch already satisfied the expression. With assessment scope, every matching record refers to one submission. Account results choose the newest submission that satisfies the whole expression. With account scope, each term uses its newest retained matching submission. These assessment IDs can differ. The account’s latest and current values keep their separate meanings. Deleting or expiring one term’s only matching submission can exclude an account from an AND search. Another retained matching submission can preserve it. Account deletion excludes all its matches. Expression searches keep the existing ordering, count limits and live-page rules below. Accounts appear once, even when several submissions or branches match. The count describes distinct accounts on account search and assessments on assessment search. A cursor binds the scope, ordered expression, original term values and other filters. Keep operand order, grouping, values and match rules unchanged. Omitting match means exact and does not change that binding. Equivalent spelling or Boolean rearrangement still changes the filter. Changing only limit is allowed.
TypeScript
All seven SDKs expose IdentifierExpression and IdentifierTermMatch models. Python supports the same filter on synchronous and asynchronous search methods. The MCP tools accept the wire shape under request.identifier_expression.

Choose the match rule

exact is the default. It compares the original submitted text, including case and formatting. NoResponse preserves the original value for every mode. For example, canonical email matches Jane.Doe+case@EXAMPLE.COM with Jane.Doe+case@example.com, while retaining the capitalised local part and tag. It does not match jane.doe@example.com. Choose mailbox when you intentionally want the existing alias rules. Those rules are a matching policy, not proof of who controls either address. Email and username search values follow the syntax accepted for submitted identifiers, including Unicode local parts and usernames. Email is bounded to 254 characters overall and 64 in its local part. Usernames are 1 to 64 characters. Controls, invisible format characters and whitespace are refused. Phone queries allow up to 64 characters so a canonical query can include formatting. An accepted submission itself is strict E.164. The canonical phone rule ignores spaces, hyphens, periods and parentheses, and the optional domestic (0) after an explicit country code. Country codes 39, 378 and 379 keep that zero. This is syntax matching, not verification that a number is assigned or controlled by the account. Explicit mailbox mode keeps the legacy list validator’s byte bounds after NFC and lowercasing. The local part can contain up to 64 UTF-8 bytes. The full address can contain up to 254 bytes. Applying alias rules must leave a nonempty local part. An admitted Unicode address can therefore be valid for exact and canonical but return 400 invalid_request for mailbox. Use the first two modes for its submitted-value searches. Selecting mailbox mode does not relax these bounds. A username query is explicit about its scope:
Customer username filter
NoResponse does not equate this name with a handle on GitHub, Instagram or another platform. A source-discovered association remains source evidence. Search does not turn it into a submitted identifier, verified ownership claim or account merge. The search contract has no discovered-provenance selector.

Read why an item matched

A single-identifier search adds matched_identifier to each item. It contains the original value, kind, match_basis, provenance: "submitted", matching assessment_id, and the username namespace when applicable. For an account, it identifies the most recent retained assessment that matched. The account’s latest assessment may contain a different identifier. The account row’s current contains its current account decision and score. When current is absent, show No current decision. The latest assessment score does not fill that gap. The match describes deterministic equality and does not assign an ownership confidence score.

Limits, permissions and page changes

Search is limited to the authenticated workspace and environment. It requires history or investigation access. Filtering by an identifier also requires permission to read identifiers. API keys need legacy history, or investigate with evidence/detailed. Console members need the corresponding current capabilities. Detailed assessment responses have their own evidence permission. Revoked access is checked again on every request. Use one of identifier_expression, identifier or the legacy email field. All other supported filters combine with AND. Account search also supports exact account_id and needs_action, combined with the identifier using AND. needs_action additionally requires review access for console members or management for API keys and returns waiting_for reasons. Work through those accounts with Reviews. Assessment search keeps its existing time, decision, revision, evidence and score filters and their combination rules below. Limits are 1 to 50 items, default 25 accounts or 20 assessments. Every page includes total and total_capped. The count is exact below 10,000. At or above 10,000 the count is capped and total_capped is true. Unsupported identifier kinds, namespaces, modes and invalid values return 400 invalid_request. Missing authentication returns 401. Insufficient current access returns 403. Pass next_cursor with unchanged filters. A cursor is opaque, expires, and is bound to its operation, workspace, environment and filters. A modified, expired or cross-scope cursor returns 400 invalid_cursor. Single and combined identifier account searches use stable opaque account order, so repeated assessments do not move an existing account across the cursor. Assessment results use creation time with an ID tie break. The original directory and legacy email searches keep their existing order. Items and totals share one database snapshot within a page. Pages are live and do not share a snapshot. A new match before the cursor needs a fresh search. Deletion, erasure, expiry or changed filter membership can exclude later results. Current account risk is read separately and can advance during a page. Start a new search to refresh the entire result set. Historical submitted values stay searchable only while their originating assessment is retained. Deleting or erasing that assessment excludes its match. Deleting an account excludes all of its matches. Effective retention applies at read time as well as cleanup. Values from before original inputs were retained cannot be reconstructed. For older retained assessments with available original inputs, the existing maintenance worker and search requests catch up the index in bounded batches. While catch-up is incomplete, the API returns 503 service_unavailable with Retry-After instead of a partial page or total. Retry the same query after that interval. A successful page covers all eligible retained originals in that page’s database snapshot. Historical assessments whose originals were not retained are outside this guarantee.

Call the public SDK

Search by submitted email
Python also provides search_async on both resources. Account search keeps its existing operation envelope: read the page from .result, with headers on the response. Assessment search keeps its existing direct-page return. The generated Go, Java, C#, PHP and Ruby clients use the same IdentifierSearch and IdentifierMatch models. The MCP server exposes search_accounts and search_assessments, with the filter under request.identifier. The API checks the caller’s permissions for every tool call.

List linked accounts

GET /v1/accounts/{account_id}/links lists the other accounts in the same workspace and environment that submitted an email, phone or username that this account also submitted. It runs the account’s own retained submitted identifiers through the same match rules as search, so you do not search each identifier by hand. The account itself is not listed.
Linked account page
Each linked account has one shared_identifiers entry for each shared kind, in the order email, phone, username. The entry uses the strictest rule that links the two accounts: exact, then canonical, then mailbox. account and linked_account each name that account’s most recent retained assessment that submitted the identifier, with the original value and submitted_at. Under canonical or mailbox the two values can differ. A shared identifier is evidence that both accounts submitted it, not proof that one person owns both. Only submitted identifiers link accounts. Identifiers that a source found do not. An expired or deleted assessment links nothing, on either side. An account with no retained assessments returns an empty page. Pass limit (1 to 50, default 25) and cursor as query parameters. Accounts come in a stable order. total counts distinct linked accounts, exactly below 10,000. The cursor is bound to the account, workspace and environment. A changed or expired cursor returns 400 invalid_cursor. The permissions are those of identifier search: an API key needs history, or investigate with evidence, and a console member needs history and evidence access in that environment. While older assessments are still being indexed the API returns 503 service_unavailable with Retry-After.
List linked accounts
Python also provides list_linked_async. The MCP server exposes list_linked_accounts, with account_id, limit and cursor under request. In the console, the account page and the assessment page list linked accounts and link to each one.

Search and get exact decisions

POST /v1/assessments/search searches the calling key’s environment. Supply an inclusive from and exclusive to, no more than 366 days apart. Optional filters are account, flow, status, assessment recommendation and assessment decision. With "revision": "first", the filters apply to each assessment’s first answer and search returns that answer. Use it to find the assessments behind a count from Assessment counts. You can also filter by band, reason, impact, incomplete lane, country, asn, score_min, score_max and list_match. Filters combine with AND. impact requires a reason, and score bounds are inclusive. Pending answers without a score do not match score filters. list_match accepts allow, block or none and requires revision: first. none means NoResponse captured that no list entry matched. Older answers without captured list state do not match any of these values. The legacy email filter keeps its account-wide mailbox behavior. Search finds each account that sent that mailbox in one of its retained assessments. It returns every assessment of those accounts, also the assessments that sent another address. The mailbox matches as a list entry does. Case does not matter and NoResponse ignores a +tag. At gmail.com and googlemail.com, it also ignores the dots of the local part. So Jane.Doe+promo@googlemail.com finds janedoe@gmail.com. An address without a mailbox answers 400. A search by email needs the permission that reads identifiers. For an API key, that is history, or detailed with investigate or exports. A workspace member needs the evidence permission. Pass changed: true to find the assessments whose latest decision differs from their first answer’s, such as an allow that a late result turned into block. changed: false finds the others. An assessment whose first answer had no decision yet is not changed. changed cannot be combined with revision: "first". Pages have at most 50 items. Pass next_cursor back with the same filters. Each page has total, the number of assessments that match the filters across every page, and total_capped. total is exact up to 10,000. At 10,000 or more matches it is 10,000 and total_capped is true.
Search assessments
Search returns the latest retained version of each matching assessment. Results can change between pages as work settles, and so can total. The existing account-only history query keeps its behavior. Each item also has first_decision, the decision of the assessment’s first answer, so you can show what changed without another read. It is absent when the first answer had no decision yet. Use decision: "block" to find blocked assessments. The decision is block when the stored assessment has risk.block: true. Otherwise, it is the recommendation. Later account feedback or shared-key changes do not change this filter. recommendation and decision combine with AND. Neither filter means the account’s current decision. Get an exact assessment with GET /v1/assessments/{assessment_id}/versions/{version}. It includes the original policy, flow, depth and decision. It excludes the current account projection. Get an exact account decision with GET /v1/accounts/{account_id}/decisions/{risk_version}. It identifies the original assessment version and the feedback report that applied. Its risk includes the shared-key state that applied then. A version from before capture began returns 404, not a reconstruction from current data. Both operations need investigate or history. A detailed assessment view also needs evidence or detailed. Submitted identifiers require that sensitive evidence access too.

Diagnose an HTTP attempt

GET /v1/requests needs history. Supply from and to for a range of at most seven days. Optional filters are request_id, normalized route, and HTTP status. Pages have at most 100 records. Each attempt has a separate id, even when retries share an X-Request-ID. Assessment attempts include the exact public decision prepared for that response. write_complete means the server wrote and flushed the response. It does not prove your platform processed it. Diagnostics exclude request bodies, authorization values and source payloads. NoResponse keeps them for seven days or the shorter environment retention. Capture has a bounded time budget to protect response latency. Infrastructure failures can leave gaps. Private metrics count failed diagnostic writes. Check this count and query coverage before using diagnostics for evaluation. An incomplete collection cannot establish complete operational coverage. Routes use templates without path values. Credential operations use issued_keys in diagnostic templates to preserve the label through security filtering. Their HTTP paths remain /credentials.

Bind a provisional account

A hosted pre_registration check can return a provisional id: pre: followed by the assessment id. After your auth provider creates the user, bind the assessment to the stable opaque account id:
Bind the account
The operation needs assess. It creates a new assessment version and keeps earlier versions. Pending work continues on that assessment and updates the stable account. Repeating the same binding returns the original receipt. A different target returns binding_conflict. Bind before adding outcomes, enforcements or issued keys to the provisional account. This operation does not merge arbitrary accounts. Keep the binding receipt and use the stable id for later actions. While the binding exists, deleting either name deletes the bound account. The binding expires with its assessment. Use the stable id for later data requests.

Associate keys issued by your platform

POST /v1/accounts/{account_id}/credentials accepts {"sha256":"<64 lowercase hex characters>"} and needs assess. Compute the hash from a high-entropy key issued by your platform. Send the hash, never the key. The operation returns a new association id or the original record for a repeated hash. A hash linked to another account returns a conflict. GET /v1/accounts/{account_id}/credentials lists associations and needs history. DELETE /v1/accounts/{account_id}/credentials/{credential_id} retires an association and needs delete. Retirement keeps its first actor and time. It is safe to repeat. Retirement excludes the association from risk calculations. Revoke the actual key through your platform. Repeating registration after retirement keeps the association retired. Usage batches for active associations use the existing shared-key rules. Historical decisions keep their original shared-key state. Associations remain while retained account activity needs them. Retired records prevent old assessment links from activating the association again. Deleting the account deletes these associations immediately.

Export an account

GET /v1/accounts/{account_id}/export needs exports and investigate, or the legacy history scope. It returns one consistent snapshot of retained records. Detailed assessment fields also need evidence or detailed. Each assessment revision in the export carries detail.identifiers. The export includes assessments and revisions, captured account decisions, outcomes, binding receipts, key associations, enforcements and request diagnostics. The response names its exclusions. These include expired or deleted data, secrets, key hashes, restricted source records and other workspaces’ data. It also excludes legacy free-text notes and historical decisions from before capture began. complete describes the retained records within those boundaries. A synchronous export supports at most 10,000 records and 8 MiB. Larger accounts return export_too_large, never a truncated success. For a larger account, create an asynchronous export with POST /v1/workspaces/{workspace_id}/exports. Choose kind: account, the account id and the environment. Poll the returned job, then download its numbered chunks before expiry. Each download checks your current permissions. An asynchronous job permits up to 64 MiB. Artifacts expire within 24 hours, or sooner when their source retention ends. Use paged history and search for larger collections. Account exports exclude investigator reviews. Export a review separately with review and export access. For the job lifecycle, chunk downloads, cancellation, retries and limits, see Export jobs.

Evaluate a threshold change

Keep the first served decision, the outcome learned later, and every correction. Use the decision from before the first outcome observation or receipt. Include the cutoff from a report that a correction later replaced. Count each canonical account once. Several assessments or a provisional id must not create extra samples. Unknown and unlabeled users are not known legitimate users. Your reports are assertions, so document how your team collected the labels. Set aside accounts for a holdout before choosing thresholds. Compare false positives, abuse detection, review volume, latency, unavailable results, service errors and missing diagnostics. Include unlabeled accounts when measuring review volume. Synthetic outcomes test integration behavior, not production accuracy. Apply reviewed changes through the existing settings operation. A change affects new assessments. It does not rewrite historical decisions.