Skip to main content

External service policy API reference

Beta

This feature is in Beta. Workspace admins can control access to this feature from the Previews page by opting into the Unity Gateway Service Policies preview. See Manage workspace-level previews.

When a customer attaches an external service policy to a service, Unity Gateway calls a guardrail vendor's HTTP endpoint on each governed interaction and enforces the verdict that the endpoint returns. This page describes the contract that the endpoint implements: the request Databricks sends, the response it expects, and how it handles each response.

Use this page to build an endpoint that customers can use with external service policies, or to check that a vendor's endpoint is compatible. For the customer setup, see Enforce a partner guardrail with an external service policy.

How it works​

On each governed interaction, Databricks sends a POST request with a JSON body to the endpoint. The endpoint inspects the content and returns ALLOW, DENY, or, for an MCP tool call, ASK, and Databricks enforces the verdict.

One endpoint can serve many customers and policies. A customer chooses the behavior they want with the policy configuration, which Databricks passes to the endpoint on every request.

Endpoint requirements​

The endpoint must:

  • Accept POST requests with a JSON body at the host and path that the customer configures on the connection.
  • Accept OAuth machine-to-machine (M2M) authentication. The customer configures a client ID, a client secret, your token endpoint, and optional scopes on the connection. Databricks gets an access token from your token endpoint and sends it in the Authorization header of each request. Your token endpoint must return tokens in the format the OAuth 2.0 specification defines. See External services must comply with OAuth 2.0 specifications.
  • Use HTTPS. Databricks doesn't call an endpoint over plain HTTP.
  • Respond within 5 seconds. Databricks denies the interaction when the endpoint doesn't respond in time.
  • Return HTTP 200 with a JSON verdict for every decision, including a block, in a response body no larger than 64 KB.

If the endpoint supports more than one behavior, such as different detection profiles, tell customers what to enter as the policy configuration.

Request​

Databricks sends each evaluation as an HTTP request to the connection's host and path. The path is / when the connection has none.

HTTP
POST /<path> HTTP/1.1
Host: <host>
Authorization: Bearer <access-token>
Content-Type: application/json

The body is a JSON object with two members:

JSON
{
"event": {},
"config": {}
}
  • event is the interaction under evaluation. See The event object.
  • config holds the policy's options, including the customer's policy configuration. See The config object.

The event object​

Field

Type

Description

type

String

The interaction and phase: tool_call, tool_result, model_call, or model_result. Present in every event. See Event types.

target

String

The three-level name of the governed service in Unity Catalog, for example main.default.github_mcp. Present in every event.

data

Object

The content under evaluation. Its shape depends on type. Present in every event.

request_data

Object

The originating request, so you can judge a result in the context of its request. Present on tool_result and model_result only.

api_type

String

The API format of data and request_data. Present on model_call and model_result only. See API types.

trace_id

String

The OpenTelemetry trace ID of the governed request. Use it to match an evaluation in your logs to the request. Present only when the request has a trace, so don't require it.

Field

Type

Description

type

String

The interaction and phase: tool_call, tool_result, model_call, or model_result. Present in every event. See Event types.

target

String

The three-level name of the governed service in Unity Catalog, for example main.default.github_mcp. Present in every event.

data

Object

The content under evaluation. Its shape depends on type. Present in every event.

request_data

Object

The originating request, so you can judge a result in the context of its request. Present on tool_result and model_result only.

api_type

String

The API format of data and request_data. Present on model_call and model_result only. See API types.

trace_id

String

The OpenTelemetry trace ID of the governed request. Use it to match an evaluation in your logs to the request. Present only when the request has a trace, so don't require it.

The event carries content only. It doesn't include the identity of the user, agent, or app that made the call.

Event types​

type

Service and phase

data

request_data

tool_call

MCP Service, before the tool runs

{"name": "<tool>", "arguments": {...}}

Not present

tool_result

MCP Service, after the tool runs

The tool's result

{"name": "<tool>", "arguments": {...}}, the originating call

model_call

Model Service or Model Provider Service, before the model is called

The full model request body, in the format named by api_type

Not present

model_result

Model Service or Model Provider Service, after the model responds

The full model response body, in the format named by api_type

The full model request body

type

Service and phase

data

request_data

tool_call

MCP Service, before the tool runs

{"name": "<tool>", "arguments": {...}}

Not present

tool_result

MCP Service, after the tool runs

The tool's result

{"name": "<tool>", "arguments": {...}}, the originating call

model_call

Model Service or Model Provider Service, before the model is called

The full model request body, in the format named by api_type

Not present

model_result

Model Service or Model Provider Service, after the model responds

The full model response body, in the format named by api_type

The full model request body

A model request body includes the messages in the request, such as the system prompt and earlier turns of the conversation. If the customer sets a conversation window for the policy, the body can hold only the most recent messages, so don't assume that the full conversation is present.

API types​

Model events carry the request and response bodies in the API format that the caller used. Databricks doesn't convert them to a common format. The api_type field names the format:

api_type

Format

mlflow/v1/chat/completions

Databricks chat completions, compatible with OpenAI Chat Completions

mlflow/v1/completions

Databricks completions

mlflow/v1/embeddings

Databricks embeddings

mlflow/v1/responses

Databricks Open Responses

openai/v1/chat/completions

OpenAI Chat Completions

openai/v1/completions

OpenAI Completions

openai/v1/embeddings

OpenAI Embeddings

openai/v1/responses

OpenAI Responses

anthropic/v1/messages

Anthropic Messages

gemini/v1/generateContent

Gemini generateContent

gemini/v1/streamGenerateContent

Gemini streamGenerateContent

cursor/v1/chat/completions

Cursor chat completions

codex/v1/responses

Codex Responses

typesafe/v1/systemone

System One

api_type

Format

mlflow/v1/chat/completions

Databricks chat completions, compatible with OpenAI Chat Completions

mlflow/v1/completions

Databricks completions

mlflow/v1/embeddings

Databricks embeddings

mlflow/v1/responses

Databricks Open Responses

openai/v1/chat/completions

OpenAI Chat Completions

openai/v1/completions

OpenAI Completions

openai/v1/embeddings

OpenAI Embeddings

openai/v1/responses

OpenAI Responses

anthropic/v1/messages

Anthropic Messages

gemini/v1/generateContent

Gemini generateContent

gemini/v1/streamGenerateContent

Gemini streamGenerateContent

cursor/v1/chat/completions

Cursor chat completions

codex/v1/responses

Codex Responses

typesafe/v1/systemone

System One

Unity Gateway can add API types as it supports more APIs. Treat an api_type you don't recognize as content you can't parse, and return a deliberate verdict for it, such as DENY.

The config object​

config holds the policy's options as strings. It doesn't include the connection or path.

Field

Type

Description

policy_config

String

The policy configuration exactly as the customer entered it, as a JSON object passed in a string. Parse the string as JSON, for example "{\"profile\": \"strict\"}". Databricks doesn't read this value. Not present when the customer leaves it empty.

phases

String

The phases the policy runs on: pre_call, post_call, or pre_call,post_call.

Field

Type

Description

policy_config

String

The policy configuration exactly as the customer entered it, as a JSON object passed in a string. Parse the string as JSON, for example "{\"profile\": \"strict\"}". Databricks doesn't read this value. Not present when the customer leaves it empty.

phases

String

The phases the policy runs on: pre_call, post_call, or pre_call,post_call.

config can include other policy options. Ignore keys you don't recognize.

Request examples​

An MCP tool call, before the tool runs:

JSON
{
"event": {
"type": "tool_call",
"target": "main.default.github_mcp",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"data": {
"name": "create_issue",
"arguments": { "repo": "acme/website", "title": "Bug: checkout returns 500" }
}
},
"config": {
"policy_config": "{\"profile\": \"strict\"}",
"phases": "pre_call"
}
}

An MCP tool result, after the tool runs:

JSON
{
"event": {
"type": "tool_result",
"target": "main.default.github_mcp",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"data": { "content": [{ "type": "text", "text": "Issue #4213 created" }] },
"request_data": { "name": "create_issue", "arguments": { "repo": "acme/website" } }
},
"config": {
"phases": "pre_call,post_call"
}
}

A model request, before the model is called:

JSON
{
"event": {
"type": "model_call",
"target": "main.default.support_assistant",
"api_type": "mlflow/v1/chat/completions",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"data": {
"messages": [
{ "role": "system", "content": "You are a support agent." },
{ "role": "user", "content": "My card number is 4111 1111 1111 1111. Please refund me." }
],
"max_tokens": 512
}
},
"config": {
"phases": "pre_call"
}
}

A model response, after the model responds:

JSON
{
"event": {
"type": "model_result",
"target": "main.default.support_assistant",
"api_type": "mlflow/v1/chat/completions",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"data": { "choices": [{ "message": { "role": "assistant", "content": "Here is your refund link." } }] },
"request_data": { "messages": [{ "role": "user", "content": "Please refund me." }] }
},
"config": {
"phases": "post_call"
}
}

Response​

Return HTTP 200 with a JSON body:

JSON
{
"result": "DENY",
"reason": "The message contains a payment card number."
}

Field

Type

Description

result

String

Required. ALLOW, DENY, or ASK. The value is case-insensitive. Return ASK only for a tool_call event. See Hold a tool call for approval.

reason

String

Optional. On DENY, Databricks returns it to the caller. When it's empty or missing, the caller gets the default reason: "Access denied: this request is not permitted by a policy on this service."

Field

Type

Description

result

String

Required. ALLOW, DENY, or ASK. The value is case-insensitive. Return ASK only for a tool_call event. See Hold a tool call for approval.

reason

String

Optional. On DENY, Databricks returns it to the caller. When it's empty or missing, the caller gets the default reason: "Access denied: this request is not permitted by a policy on this service."

Return a block as a DENY verdict with HTTP 200, not as an HTTP error. Databricks treats an HTTP error as a failed evaluation, so it denies the interaction, but the caller doesn't see your reason.

External service policies can't redact or rewrite content, so don't return a modified payload.

Hold a tool call for approval​

On a tool_call event, return ASK to hold the tool call until the user approves it. If the user approves, Databricks runs the tool call. Return ASK only for a tool_call event:

  • On a tool_result event, ASK doesn't block. The result goes through as if you returned ALLOW. To block a result, return DENY.
  • On a model_call or model_result event, Databricks blocks the interaction, because Model Services and Model Provider Services can't ask the user for approval.

How Databricks handles each response​

External service policies fail closed. Databricks denies the interaction whenever it can't read a verdict from the endpoint:

Response

What Databricks does

result is ALLOW

Allows the interaction.

result is DENY

Denies the interaction and returns your reason, or the default reason.

result is ASK

On a tool_call, holds the tool call until the user approves it. On a tool_result, allows the result. On a model event, denies the interaction.

result is missing, empty, not a string, or an unrecognized value

Denies the interaction.

The body isn't valid JSON, or it has a top-level error member

Denies the interaction.

The body is larger than 64 KB

Denies the interaction.

The HTTP status isn't 2xx

Denies the interaction.

No response within 5 seconds

Denies the interaction.

The connection fails

Denies the interaction.

Response

What Databricks does

result is ALLOW

Allows the interaction.

result is DENY

Denies the interaction and returns your reason, or the default reason.

result is ASK

On a tool_call, holds the tool call until the user approves it. On a tool_result, allows the result. On a model event, denies the interaction.

result is missing, empty, not a string, or an unrecognized value

Denies the interaction.

The body isn't valid JSON, or it has a top-level error member

Denies the interaction.

The body is larger than 64 KB

Denies the interaction.

The HTTP status isn't 2xx

Denies the interaction.

No response within 5 seconds

Denies the interaction.

The connection fails

Denies the interaction.

Customers can't configure an external service policy to allow traffic when the endpoint fails.

When Databricks calls the endpoint​

  • Databricks calls the endpoint one time for each phase the policy runs on: before the service is called, after it responds, or both. A policy that runs on both phases sends two requests for each interaction.
  • When the customer attaches the policy in Log mode, Databricks still calls the endpoint and records your verdict, but doesn't enforce it.
  • A DENY from another policy that runs before the external service policy can stop the interaction before Databricks calls your endpoint. See Order of evaluation.

Data handling​

Each request carries customer content: model request and response bodies, including system prompts and earlier messages, and MCP tool names, arguments, and results. Handle it as customer data, and document for customers what your endpoint stores, for how long, and where it processes the content.

Test your endpoint​

Before customers use your endpoint, send it a sample request and check that it returns HTTP 200 with a result of ALLOW, DENY, or ASK in under 5 seconds:

Bash
curl -X POST "https://api.example.com/ai-security/v1" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"event": {"type": "tool_call", "target": "main.default.github_mcp", "data": {"name": "create_issue", "arguments": {"repo": "acme/website"}}}, "config": {"policy_config": "{\"profile\": \"strict\"}", "phases": "pre_call"}}'

To test the full flow, attach an external service policy that uses your endpoint to a service in a Databricks workspace, in Log mode, and review the recorded verdicts in the unified trace table. See Enforce a partner guardrail with an external service policy.

Next steps​