Skip to main content
Use the Sessions API to retrieve stored result summaries after the browser handoff completes.
Sessions endpoints require a secret key and never return collect-time sealed handoff tokens. Each endpoint also requires a scope on the key: sessions:list, sessions:read, or sessions:update. See Authentication.

Endpoint summary

GET /v1/sessions

Returns one row per session with the latest decision summary. Requires a secret key with the sessions:list scope. The default scopes for a secret key don’t include sessions:list, so add it to keys that list sessions. Supported query parameters: Rows are ordered by the time of each session’s latest decision, newest first. A limit, verdict, client_user_id, or cursor value that isn’t valid returns 422 with request.validation_failed, and the offset parameter isn’t supported. See Pagination for how to page through results. search matches in one of two ways:
  • A value that starts with sid_, evt_, or vid_ matches a session ID, event ID, or visitor ID exactly, ignoring case. A 32-character hexadecimal value matches a legacy session ID or event ID exactly.
  • Any other value is a case-insensitive substring match against the session ID, event ID, visitor ID, client_user_id, page URL, user agent, and IP address.
Example response:
In each row, latest_decision carries these fields:

Look up a user’s sessions

After you attach your own user ID to sessions with PATCH /v1/sessions/:sessionId, pass the same value as client_user_id to list every session for that user:
The match is exact and case-sensitive. Foil trims surrounding whitespace from the value, as it does when you attach one, and an empty value or one longer than 256 characters returns 422. You can combine client_user_id with verdict and search, and page through the results with cursor as usual; send the same client_user_id with each cursor. To read the signals for a session in the list, retrieve it with GET /v1/sessions/:sessionId. Use client_user_id rather than search to find a user’s sessions. search matches substrings across several fields, so it can also return sessions for other users whose IDs contain the value.

GET /v1/sessions/breakdown

Counts the sessions that match a set of filters, grouped by one dimension, with the number of bot, human, and inconclusive verdicts in each group. Use it to answer questions such as which browsers account for the sessions from one city, or which networks the bots on a platform come from. Requires a secret key with the sessions:list scope. Supported query parameters: Each group’s value is in the form its filter parameter accepts, so you can pass it back to this endpoint as a filter to narrow further. For city groups, pass the group’s country_code as country along with the city. GET /v1/sessions filters only by verdict and client_user_id (and search), so it can list the sessions in a verdict group or for one user, but not in a browser, platform, location, or network group. A test key counts test sessions and a live key counts live sessions. An unknown parameter, a value that isn’t valid, or a parameter that is empty or given more than once returns 422 with request.validation_failed. Foil rejects these rather than ignoring them so that a misspelled or malformed filter can’t return counts for sessions you didn’t ask about. A breakdown that doesn’t finish within 20 seconds returns 503; narrow since and until or add filters, then retry. Counts include new decisions within about five minutes. For example, to see the top browsers among sessions from Austin in September:
Example response:
Sessions whose platform or browser Foil doesn’t recognize are grouped under other when you group by platform or browser. An iPad that requests desktop websites is counted as macos.

GET /v1/sessions/:sessionId

Requires a secret key with the sessions:read scope. A session that doesn’t exist, or that belongs to the other environment, returns 404 with request.not_found. Returns the full public investigation view for one session. The response is intentionally ordered so the most actionable fraud analysis appears first, followed by continuity context, then structured evidence and lower-level telemetry. Unlike GET /v1/sessions, which stays a compact summary surface with latest_decision, session detail uses the richer decision, highlights, signals_fired, and client_telemetry model shown below. Example response:
Response fields are grouped by purpose:
  • decision is the current session outcome in public, action-oriented terms. automation_status maps to automated, human, or uncertain, while decision_status tells you whether the current result is preliminary or final.
  • highlights is a curated explanation layer capped at five items, including both concerning and reassuring findings.
  • attribution, web_bot_auth, network, and runtime_integrity summarize the strongest fraud and classification context.
  • attribution.labels identifies what is behind the session. Each label has a kind (actor, provider, tool, product, organization, purpose, environment, trust, or evasion), a flat string value such as automation, ai-agent, or playwright, a display label, and a confidence from 0 to 100. attribution.behaviors describes how input reached the page, by channel. attribution is null when Foil has nothing to attribute.
  • Each runtime_integrity field is one of clean, notice, elevated, or high_risk.
  • visitor_fingerprint and connection_fingerprint provide continuity and transport identity context. visitor_fingerprint.resolution tells you how the session was linked to the visitor ID.
  • native_runtime_integrity, native_app, native_carrier, native_motion_print, device_identity, and install_id are null for browser sessions. Sessions from the iOS and Android SDKs can populate them, but each field is still null when Foil doesn’t have its data for the session, so check each one before you read it.
  • behavior is null unless behavior data is enabled for your organization and available for the session.
  • signals_fired is the structured machine-usable signal summary; highlights is the editorial explanation layer.
  • client_telemetry is curated lower-level client telemetry for investigations. It is not a verbatim raw probe dump.
signals_fired.signal and highlights.evidence.signal are friendly string slugs. They are response values, not an exhaustive documented enum registry.

PATCH /v1/sessions/:sessionId

Sets or clears client_user_id, the ID of the end user in your own database. This is customer-supplied linkage only: it does not affect scoring, visitor fingerprints, sealed tokens, or browser/native SDK behavior. Requires a secret key with the sessions:update scope.
Send null to clear it:
The body must include client_user_id. Foil applies these rules to its value: Errors are request.validation_failed responses with details.parameter_set set to session_update. A session that doesn’t exist, or that belongs to the other environment, returns 404. The response is the same session detail resource returned by GET /v1/sessions/:sessionId, with the updated client_user_id. The list endpoint returns client_user_id on each row, and its client_user_id parameter lists every session for one user.