External service policy API reference

Important

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 Azure 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, Azure 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 Azure Databricks enforces the verdict.

One endpoint can serve many customers and policies. A customer chooses the behavior they want with the policy configuration, which Azure 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. Azure 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. Azure Databricks doesn't call an endpoint over plain HTTP.
  • Respond within 5 seconds. Azure 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

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

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

The body is a JSON object with two members:

{
  "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.

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

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. Azure Databricks doesn't convert them to a common format. The api_type field names the format:

api_type Format
mlflow/v1/chat/completions Azure Databricks chat completions, compatible with OpenAI Chat Completions
mlflow/v1/completions Azure Databricks completions
mlflow/v1/embeddings Azure Databricks embeddings
mlflow/v1/responses Azure 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\"}". Azure 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:

{
  "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:

{
  "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:

{
  "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:

{
  "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:

{
  "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, Azure 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. Azure 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, Azure 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, Azure Databricks blocks the interaction, because Model Services and Model Provider Services can't ask the user for approval.

How Azure Databricks handles each response

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

Response What Azure 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 Azure Databricks calls the endpoint

  • Azure 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, Azure 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 Azure 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:

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 Azure 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