Access Decision API
Technical specification for the POST /api/v1/access-decision endpoint — Bigeye's real-time data governance gate for AI agents.
Overview
POST /api/v1/access-decision is Bigeye's real-time data governance gate for AI agents. Call it every time an agent is about to access a data source; Bigeye inspects the target tables and columns against its catalog and returns a per-asset decision — ALLOW, WARN, REQUIRE_CONFIRMATION, or DENY — plus the catalog signals that justify it.
Who calls this endpoint?
AI gateway products (TrueFoundry, Snowflake Intelligence, etc.) that mediate agent SQL access
Custom agent frameworks that want to surface data-quality and sensitivity context before executing a query
Snowflake Native App integrations that route through the Bigeye catalog
What happens server-side?
Each access object (table, column, or raw SQL statement) is resolved against the Bigeye catalog for the given workspace.
Catalog attributes are fetched per resolved asset: open data quality issues, sensitive-data findings, monitor counts, and certification status.
Per-asset decisions are computed from those attributes and combined into a single overall decision.
An agent record and conversation record are created or updated (for audit and lineage).
The full decision record is persisted to the database.
Policies are evaluated: synchronously when evaluate_policy = true, otherwise asynchronously via a Temporal workflow after the response is sent.
The full decision is returned synchronously in all cases.
Authentication
The endpoint uses Bigeye's standard session authentication. Every request must be made by a Bigeye user whose account has at least Edit access to the target workspace.
Supported auth mechanisms (same as the rest of the Bigeye API):
Personal API key — pass as a Bearer token in the Authorization header: Authorization: Bearer <api_key>
Session cookie — for browser-based callers already logged in to Bigeye
The username field in the request body is not used for authentication. It is the identity of the end-user driving the conversation (typically an email address) and is stored for audit purposes only. The Bigeye user_id of the authenticated API caller is derived independently from the session and stored alongside it.
Important for gateway integrations: The endpoint is designed to be called by a trusted service account (a Bigeye API key scoped to the target workspace) that passes the real end-user's identity in username. Never use the end-user's own Bigeye credentials for the service call.
Request Structure
POST /api/v1/access-decision — Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
access_objects | AccessObject[] | Yes | The tables, columns, or SQL statements the agent is about to access. See Access Objects below. |
workspace | int32 | Yes* | Bigeye workspace ID. Required unless the first access object carries workspace_id. A request where both disagree returns HTTP 400. |
agent_external_id | string | Recommended | Stable identifier for the agent in your system (e.g. a tool name or UUID). Used to resolve or auto-create the agent record and link conversations to it. |
conversation_external_id | string | Recommended | Your identifier for the conversation/session this call belongs to. If omitted and an agent_external_id is present, a UUID is generated automatically. |
span_external_id | string | No | Sub-conversation identifier (e.g. a tool call span). Stored for audit; not used in decision logic. |
operation | string | No | Human-readable name of the operation being performed (e.g. "read_table", "run_sql"). Stored for audit and surfaced in the Bigeye UI. |
path | string | No | File or resource path associated with the operation. Stored for audit. |
timestamp | int64 | No | When the access occurred. Accepts epoch milliseconds or epoch seconds (auto-detected: values < 10¹² are multiplied by 1 000). Defaults to the request time if omitted or ≤ 0. |
ai_agent | AiAgent | No | Agent metadata. Relevant sub-fields: id (Bigeye agent ID, bypasses external-id lookup), name (display name for auto-creation), platform (see Platforms), description. |
evaluate_policy | bool | No | When true, workspace policies are evaluated synchronously and their decisions are included in the response. Default false (async evaluation). |
initial_prompt | string | No | The first user message that opened this conversation. Stored on the conversation record. |
username | string | No | Email (or other identifier) of the end user driving this conversation. Stored for audit; not used for authentication. |
*Workspace resolution: if workspace is absent, the workspace_id from the first access object is used. One of the two must be present. | |||
Supported platform values (the AiPlatform enum): |
| Value | Platform |
|---|---|
AI_PLATFORM_SNOWFLAKE | Snowflake Intelligence / Cortex |
AI_PLATFORM_DATABRICKS | Databricks |
AI_PLATFORM_LANGCHAIN | LangChain |
AI_PLATFORM_COPILOT | GitHub Copilot |
AI_PLATFORM_AGENTFORCE | Salesforce Agentforce |
AI_PLATFORM_CLAUDE | Anthropic Claude |
AI_PLATFORM_CURSOR | Cursor |
AI_PLATFORM_BEDROCK | Amazon Bedrock |
AI_PLATFORM_TRUEFOUNDRY | TrueFoundry |
AI_PLATFORM_COPILOT_STUDIO | Microsoft Copilot Studio |
Access Objects
Each entry in access_objects describes one thing the agent is accessing. Three types are supported:
| Field | Type | Description |
|---|---|---|
type | AccessObjectType | ACCESS_OBJECT_TYPE_TABLE, ACCESS_OBJECT_TYPE_COLUMN, or ACCESS_OBJECT_TYPE_SQL |
external_id | string | Fully-qualified name of the asset, or raw SQL text for the SQL type (see below) |
source_type | WarehouseType | Warehouse vendor enum (e.g. WAREHOUSE_TYPE_SNOWFLAKE, WAREHOUSE_TYPE_BIGQUERY) |
source_name | string | Name of the specific Bigeye data source (warehouse connection). Used for catalog lookup when id is absent. |
id | int32 | Bigeye catalog ID for the asset. When provided, bypasses name-based lookup. |
source_id | int64 | Bigeye warehouse ID. Set by the server in the response; not required on input. |
workspace_id | int32 | Workspace the asset belongs to. Required when workspace is absent from the top-level request. |
TABLE type
external_id must be the fully-qualified table name in the three-part database.schema.table format used by Snowflake, BigQuery, Databricks, Redshift, and PostgreSQL.
Partially-qualified names (e.g. schema.table) cannot be pinned to a specific warehouse object and are treated as unresolved — they will appear in the response with no catalog attributes.
{
"type": "ACCESS_OBJECT_TYPE_TABLE",
"source_type": "WAREHOUSE_TYPE_SNOWFLAKE",
"source_name": "prod-snowflake",
"external_id": "MY_DB.SALES.ORDERS",
"workspace_id": 42
}COLUMN type
external_id must be the fully-qualified column name in four-part database.schema.table.column format.
{
"type": "ACCESS_OBJECT_TYPE_COLUMN",
"source_type": "WAREHOUSE_TYPE_SNOWFLAKE",
"source_name": "prod-snowflake",
"external_id": "MY_DB.SALES.ORDERS.CUSTOMER_EMAIL",
"workspace_id": 42
}SQL type
external_id contains the raw SQL text of the query the agent is about to run. Bigeye parses it to extract all referenced tables and columns, then resolves each against the catalog. The SQL is never executed by Bigeye.
SQL parsing requires source_name (to identify the warehouse vendor and dialect) and workspace_id.
{
"type": "ACCESS_OBJECT_TYPE_SQL",
"source_name": "prod-snowflake",
"external_id": "SELECT customer_email, order_total FROM sales.orders WHERE created_at > '2026-01-01'",
"workspace_id": 42
}Table + column deduplication
When both a table and its columns appear in the same request (e.g. from SQL parsing), the table's decision is scoped to table-level signals only (pipeline reliability monitors: freshness and volume). Sensitive-data findings and column-level monitors are reported on the column entries, which already cover those signals. This prevents double-counting and keeps the overall decision accurate.
Decision Logic
Each resolved asset is scored against two signals from the Bigeye catalog, then the per-asset decisions are combined into an overall decision by taking the most severe.
Per-asset signals
| Attribute key | What it counts |
|---|---|
numOpenIssues | Open data quality issues on the asset right now |
numSensitivities | Sensitive data columns found by Bigeye's data scanner |
numActiveMetrics | Number of active quality monitors configured for the asset |
certificationStatus | Raw value of the workspace's configured certification catalog attribute |
hasScanHistory | Whether the asset has ever been scanned for sensitive data |
scanJobId / scanRunId | IDs of the scan run that produced the current findings (for linking in the UI) |
tableLevelOnly | true when this table is accessed alongside its own columns; its decision covers only pipeline reliability signals |
Decision levels (most severe wins)
| Decision | Enum value | Meaning |
|---|---|---|
| DENY | ACCESS_DECISION_DENY | Block the agent from accessing this asset |
| REQUIRE_CONFIRMATION | ACCESS_DECISION_REQUIRE_CONFIRMATION | Human must approve before the agent proceeds |
| WARN | ACCESS_DECISION_WARN | Proceed, but surface a warning to the user |
| ALLOW | ACCESS_DECISION_ALLOW | No concerns; proceed normally |
| (not evaluated) | ACCESS_DECISION_UNSPECIFIED | Asset is not in the Bigeye catalog; no decision was made |
Precedence order when combining: DENY > REQUIRE_CONFIRMATION > WARN > ALLOW. An asset not in the catalog returns UNSPECIFIED and does not contribute to the overall decision. |
Configurable thresholds
The decision triggered by each signal is configurable per workspace via Bigeye's Advanced Settings:
| Setting key | Default | What it controls |
|---|---|---|
feature.access_decision.when_open_issues | ACCESS_DECISION_DENY | Decision when numOpenIssues > 0 |
feature.access_decision.when_sds_findings | ACCESS_DECISION_DENY | Decision when numSensitivities > 0 |
access.policy.always_evaluate_synchronously | false | Force synchronous policy evaluation on every request, regardless of the evaluate_policy flag |
| Both default to DENY. A workspace can lower them to WARN or REQUIRE_CONFIRMATION to allow agents to proceed with a warning instead of being blocked. |
Overall decision
The overall decision depends on whether policies were evaluated synchronously. Without synchronous policy evaluation (default): the most severe per-asset decision across all resolved assets. With synchronous policy evaluation (evaluate_policy = true, or access.policy.always_evaluate_synchronously is on): set solely by the policy engine — ACCESS_DECISION_DENY if any policy matched, ACCESS_DECISION_ALLOW otherwise. Attribute-based signals do not affect the overall decision in this mode.
Response Structure
Top-level fields
| Field | Type | Description |
|---|---|---|
overall_decision | AccessDecision | The most severe decision across all resolved assets (and policy matches, if evaluated). |
access_object_decisions | AccessObjectDecision[] | One entry per resolved asset, in the order they were resolved. Unmatched catalog assets appear last. |
unresolved_access_objects | AccessObject[] | Access objects that could not be resolved at all (e.g. source_name did not match any warehouse, or the object type was unspecified). |
policy_decisions | PolicyDecision[] | Policy evaluation results. Populated only when evaluate_policy = true or after async evaluation. |
AccessObjectDecision
Each resolved asset produces one AccessObjectDecision:
| Field | Type | Description |
|---|---|---|
access_object | AccessObject | The resolved asset, enriched with its Bigeye id, source_id, and source_name. |
access_decision | AccessDecision | The decision for this specific asset. |
reason | string | Human-readable reason for the decision (currently unused; reserved for future use). |
access_object_attributes | CatalogAttribute[] | Key-value pairs describing the asset's catalog signals. Keys: numOpenIssues, numSensitivities, numActiveMetrics, certificationStatus, hasScanHistory, scanJobId, scanRunId, tableLevelOnly. |
Unmatched catalog assets
An asset that names a fully-qualified object in a recognized warehouse vendor but has no entry in the Bigeye catalog appears as an AccessObjectDecision with:
access_decision = ACCESS_DECISION_UNSPECIFIED (no catalog data to evaluate)
source_name = "Unknown <Vendor>" (e.g. "Unknown Snowflake")
no access_object_attributes
These are included so the UI can display that the agent touched something Bigeye hasn’t cataloged yet. Partially-qualified names (fewer than three dot-separated segments) are excluded entirely and appear in unresolved_access_objects instead.
Policy Evaluation
Bigeye workspaces can define policies that inspect conversation context (agent identity, data accessed, sensitivity levels) and return a DENY or pass verdict. The access decision endpoint can evaluate these policies in two modes:
Asynchronous (default, evaluate_policy = false)
Policy evaluation is enqueued as a Temporal workflow and runs after the HTTP response is returned. policy_decisions in the response will be empty. The evaluation results are stored against the conversation record and visible in the Bigeye UI, but are not returned to the caller.
Use this mode when the gateway does not need to act on policy results in real time — e.g. when the catalog signals alone are sufficient to gate access.
Synchronous (evaluate_policy = true)
Policy evaluation runs inline before the response is returned. policy_decisions is populated with one entry per matched policy. When evaluate_policy = true, the overall decision is determined solely by the policy engine — ACCESS_DECISION_DENY if any policy matched, ACCESS_DECISION_ALLOW otherwise. Attribute-based signals (open issues, SDS findings) do not affect overall_decision in this mode.
overall_decision is ACCESS_DECISION_DENY if any policy matched, ACCESS_DECISION_ALLOW otherwise (attribute-based decisions are not consulted)
Each matched policy is listed in policy_decisions with its name and reason
Use this mode when the gateway needs a single definitive verdict and cannot act on a later async result. This is the recommended mode for inline gatekeeping.
Latency note: Synchronous policy evaluation adds latency proportional to the number of policies configured in the workspace. For most workspaces this is negligible, but at high policy counts it can be significant. Benchmark before enabling in a latency-sensitive gateway path.
Workspace-level forced evaluation
The access.policy.always_evaluate_synchronously Advanced Setting (default false) forces synchronous policy evaluation on every request regardless of the evaluate_policy flag — equivalent to all callers passing evaluate_policy = true. Use this when you want the policy engine to always gate access without requiring callers to opt in per request.
Agent and Conversation Tracking
Every access decision request is associated with an agent record and optionally a conversation record. These power the audit log, the AI Governance dashboard, and lineage edges in the Bigeye catalog.
Agent resolution
The endpoint resolves the agent in this order:
If ai_agent.id is set — look up directly by Bigeye agent ID.
If agent_external_id is set — look up by external ID within the workspace.
If agent_external_id is set but no match is found — auto-create a new agent record using agent_external_id as the stable key, ai_agent.name (or agent_external_id itself if absent) as the display name, and ai_agent.platform and ai_agent.description if provided.
If neither is set — the request is recorded without an agent association.
Auto-creation means gateway integrations do not need to pre-register agents before sending their first access decision. The first request for a new agent creates it.
Conversation tracking
Conversations group access decisions made within a single agent interaction (a "session" or "thread").
If conversation_external_id is set — it is used as the conversation's stable key. A conversation record is created on first use and reused on subsequent calls.
If conversation_external_id is omitted but agent_external_id is present — a UUID is auto-generated as the conversation ID for this request.
If neither is set — no conversation record is created.
The initial_prompt and username fields are stored only when the conversation record is first created (i.e. on the first request for a given conversation_external_id). Subsequent requests for the same conversation do not update these fields.
Lineage edges
For agents that have a corresponding lineage data node in the Bigeye catalog (currently Snowflake Intelligence agents created via the catalog sync), the endpoint automatically creates column → agent lineage edges for each column-level access object in the response. These edges are visible in the Bigeye lineage graph and used to compute agent trust scores.
Supporting Endpoints
POST /api/v1/access-decision/list
Returns stored access decision records for audit and conversation-detail views. Requires View access to the workspace.
Request fields:
| Field | Type | Description |
|---|---|---|
workspace_id | int32 | Required. Workspace to query. |
agent_external_id | string | Filter to records from this agent. |
conversation_external_id | string | Filter to records from this conversation. |
span_external_id | string | Filter to records from this span. |
Response: ListAccessDecisionRecordsResponse with a records array of AccessDecisionRecordResponse. Each record includes the full request and response JSON stored at decision time, enriched on read with the current certification status and a link to the scan run that produced any sensitive-data findings. | ||
Note: certification and open-issue counts in the stored response JSON reflect the state of the catalog at decision time. The /list endpoint can optionally refresh these to current values via workspace-level Advanced Settings (feature.access_decision.refresh_open_issues_on_list, feature.access_decision.refresh_certification_on_list). |
POST /api/v1/access-decision/summary
Returns an aggregate view of assets accessed by AI agents, used by the AI Governance dashboard. Requires View access to the workspace.
Key request fields:
| Field | Type | Description |
|---|---|---|
workspace_id | int32 | Required. |
platform | AiPlatform | Filter to a specific AI platform. |
agent_external_id | string | Filter to a specific agent. |
source_ids | int64[] | Filter to specific warehouses. |
schema_ids | int32[] | Filter to specific schemas. |
table_ids | int64[] | Filter to specific tables. |
search | string | Free-text filter on asset names. |
page_size / page_cursor | int32 / string | Pagination. |
sort_options | AccessSummarySortOption[] | Sort by warehouse name, schema name, table name, column name, monitor count, access count, or distinct agent count. |
Response: AccessSummaryResponse with summaries (one row per accessed asset), pagination_info, and filter_options (available warehouse/schema/table filters for the UI). |
Examples
Example 1: SQL query with two tables
A gateway intercepts an agent's SQL query and asks Bigeye whether the agent should be allowed to run it.
Request:
POST /api/v1/access-decision
Authorization: Bearer
Content-Type: application/json
{
"access_objects": [
{
"type": "ACCESS_OBJECT_TYPE_SQL",
"source_name": "prod-snowflake",
"external_id": "SELECT o.customer_email, o.total FROM sales.orders o JOIN sales.customers c ON o.customer_id = c.id",
"workspace_id": 42
}
],
"workspace": 42,
"agent_external_id": "my-analytics-agent-v1",
"conversation_external_id": "session-abc-123",
"operation": "run_sql",
"username": "[email protected]",
"evaluate_policy": false
}Response (DENY due to sensitive column):
{
"access_object_decisions": [
{
"access_object": {
"type": "ACCESS_OBJECT_TYPE_COLUMN",
"source_type": "WAREHOUSE_TYPE_SNOWFLAKE",
"source_name": "prod-snowflake",
"id": 1001,
"external_id": "MY_DB.SALES.ORDERS.CUSTOMER_EMAIL",
"workspace_id": 42,
"source_id": 7
},
"access_decision": "ACCESS_DECISION_DENY",
"access_object_attributes": [
{ "key": "numOpenIssues", "value": "0" },
{ "key": "numSensitivities", "value": "1" },
{ "key": "numActiveMetrics", "value": "3" },
{ "key": "certificationStatus", "value": "" },
{ "key": "hasScanHistory", "value": "true" },
{ "key": "scanJobId", "value": "88" },
{ "key": "scanRunId", "value": "2041" }
]
},
{
"access_object": {
"type": "ACCESS_OBJECT_TYPE_TABLE",
"source_type": "WAREHOUSE_TYPE_SNOWFLAKE",
"source_name": "prod-snowflake",
"id": 500,
"external_id": "MY_DB.SALES.ORDERS",
"workspace_id": 42,
"source_id": 7
},
"access_decision": "ACCESS_DECISION_ALLOW",
"access_object_attributes": [
{ "key": "numOpenIssues", "value": "0" },
{ "key": "numActiveMetrics", "value": "5" },
{ "key": "tableLevelOnly", "value": "true" }
]
}
],
"overall_decision": "ACCESS_DECISION_DENY",
"unresolved_access_objects": [],
"policy_decisions": []
}The CUSTOMER_EMAIL column has a sensitive-data finding (numSensitivities: 1), which triggers ACCESS_DECISION_DENY (the workspace default). The ORDERS table is accessed alongside its column, so it carries only table-level signals and returns ALLOW. The overall decision is the most severe across all assets: DENY.
Example 2: Direct table lookup by catalog ID
A gateway that already has the Bigeye catalog ID for a table can bypass name resolution by supplying id directly.
Request:
POST /api/v1/access-decision
Authorization: Bearer
Content-Type: application/json
{
"access_objects": [
{
"type": "ACCESS_OBJECT_TYPE_TABLE",
"id": 500,
"workspace_id": 42
}
],
"workspace": 42,
"agent_external_id": "my-analytics-agent-v1",
"conversation_external_id": "session-abc-456",
"evaluate_policy": true
}Setting evaluate_policy: true causes workspace policies to be evaluated synchronously and their verdicts included in the response's policy_decisions array. If a policy matches, overall_decision is upgraded to ACCESS_DECISION_DENY.
Updated 1 day ago
