Follow Discord
Sweep 09 Oct 2026 · 17:27Z Build v2.1.296 517 read Stable v2.1.287 Latest v2.1.296 Next v2.1.296 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · api

inference-hooks-endpoint changedmanage-claude/inference-hooks-endpoint

Nearest release: v2.1.291, published 3 hours after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Recorded here
Lines+115added
Lines−21removed
From line 158 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits12to this page, all time

## The tool call frame ### Platform tools ### Application tools ### Third-party tools ### Client tools

The whole hunk

from line 158, old and new numbered
/
lines
from line 158
158158| `User-Agent` | `anthropic-dlp/1` |
159159| `Accept-Encoding` | `identity` |
160160 
161There is one hook event today: the prompt frame, sent once per governed inference request, before inference begins. Anthropic holds the request until your AI security server responds or the verdict timeout elapses.
161There are two hook events, told apart by the top-level `type` field. The prompt frame is sent once per governed inference request, before inference begins. The tool call frame is sent when a model response contains tool calls, before any of them runs, in organizations that have turned on **Validate tool calls**. Either way, Anthropic waits until your AI security server responds or the verdict timeout elapses.
162162 
163163## The prompt frame
164164 
165165The request body is a JSON object with these fields:
166166 
167| Field | Type | Description |
168| ------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
169| `type` | string | The hook event. Always `"prompt"` today; other event types will be introduced in the future, so handle an unrecognized value gracefully (see [Forward compatibility](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#forward-compatibility)). |
170| `request_id` | string | Opaque per-inference-call identifier for correlation. Equals the `webhook-id` header. |
171| `tenant_id` | string or null | Opaque identifier for the organization the request belongs to. |
172| `actor` | object | The principal the request is attributed to, discriminated on `type` (`"user"` is the only value sent today): `id` (a tagged identifier, stable across requests for the same account) and `email_address` (when available). Both `id` and `email_address` can be null. |
173| `source` | object | The originating application: `application` (see [Source values](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#source-values)). |
174| `messages` | array | The conversation transcript up to the point of inference. See [Content blocks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#content-blocks). |
175| `session_id` | string or null | Opaque conversation identifier, when one exists. Don't parse it. For Claude Code it is a best-effort, client-asserted session identifier. |
176| `model` | string or null | Public model identifier for this request, when available. |
177| `metadata` | object | Reserved extension map of string keys to string values, sent empty today. Require nothing from it, and tolerate its absence, its presence, and any keys that appear. |
167| Field | Type | Description |
168| ------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
169| `type` | string | The hook event: `"prompt"` or `"tool_call"` (see [The tool call frame](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#the-tool-call-frame)). Other event types will be introduced in the future, so handle an unrecognized value gracefully (see [Forward compatibility](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#forward-compatibility)). |
170| `request_id` | string | Opaque per-frame identifier for correlation. Equals the `webhook-id` header. |
171| `tenant_id` | string or null | Opaque identifier for the organization the request belongs to. |
172| `actor` | object | The principal the request is attributed to, discriminated on `type` (`"user"` is the only value sent today): `id` (a tagged identifier, stable across requests for the same account) and `email_address` (when available). Both `id` and `email_address` can be null. |
173| `source` | object | The originating application: `application` (see [Source values](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#source-values)). |
174| `messages` | array | The conversation transcript up to the point of inference. See [Content blocks](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#content-blocks). |
175| `session_id` | string or null | Opaque conversation identifier, when one exists. Don't parse it. For Claude Code it is a best-effort, client-asserted session identifier. |
176| `model` | string or null | Public model identifier for this request, when available. |
177| `metadata` | object | Reserved extension map of string keys to string values, sent empty today. Require nothing from it, and tolerate its absence, its presence, and any keys that appear. |
178178 
179179An example request body:
180180 
from line 219
219219 
220220Each entry in `messages` has a `role` of `user` or `assistant` (tool results appear under the `user` role, matching the public Messages API content model) and a `content` array of blocks discriminated by `type`:
221221 
222| Block `type` | Fields |
223| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
224| `text` | `text`: the text content. |
225| `tool_use` | `id`: the identifier the matching tool result references. `tool_name`: the tool's name. `input`: the arguments the model passed to the tool. |
226| `tool_result` | `content`: the tool's output as text, with parts joined by newlines; binary parts such as images are replaced by placeholder markers, and raw bytes are never sent. `is_error`: whether the tool call failed. `tool_name`: the tool's name, so a policy can condition on tool identity without cross-referencing an earlier block. `tool_use_id`: the `id` of the matching `tool_use` block. |
227| `attachment` | `file_name`: the original file name or path. `media_type`: the attachment's media type. `size_bytes`: the size of the original file. `text`: the text content of the attachment when available, such as extracted document text, an audio transcript, or link metadata. Raw attachment bytes are never sent. |
222| Block `type` | Fields |
223| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
224| `text` | `text`: the text content. |
225| `tool_use` | `id`: the identifier the matching tool result references. `tool_name`: the tool's name. `input`: the arguments the model passed to the tool. `tool_info`: on a tool call frame only (left out elsewhere, never `null`), an object that says who provides the tool; see [The tool call frame](https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint#the-tool-call-frame). |
226| `tool_result` | `content`: the tool's output as text, with parts joined by newlines; binary parts such as images are replaced by placeholder markers, and raw bytes are never sent. `is_error`: whether the tool call failed. `tool_name`: the tool's name, so a policy can condition on tool identity without cross-referencing an earlier block. `tool_use_id`: the `id` of the matching `tool_use` block. |
227| `attachment` | `file_name`: the original file name or path. `media_type`: the attachment's media type. `size_bytes`: the size of the original file. `text`: the text content of the attachment when available, such as extracted document text, an audio transcript, or link metadata. Raw attachment bytes are never sent. |
228228 
229229Apart from `type`, a `text` block's `text`, and a `tool_result` block's `content` and `is_error`, any of these fields can be `null` when the value isn't known; for example, an image arrives as an `attachment` block with `file_name` and `text` set to `null`.
230230 
from line 244
244244 
245245Treat `source.application` as advisory routing metadata, not a trust boundary: don't rest a security-critical policy decision on it alone.
246246 
247## The tool call frame
248 
249When Claude produces tool calls, Anthropic sends one tool call frame that lists them. Calls to some of claude.ai's own tools may be left out, and a response whose only tool calls are left out doesn't produce a tool call frame; see [Availability](https://platform.claude.com/docs/en/manage-claude/inference-hooks#availability). One verdict covers the whole frame: you can't allow some tool calls and deny others. The frame goes to the same endpoint as the prompt frame, with the same headers, signature, and top-level fields. Tool calls made by code that Claude runs in the code execution tool are sent the same way, in separate tool call frames, before they run.
250 
251It differs from the prompt frame in three ways:
252 
253* `type` is `"tool_call"`.
254* `messages` holds only the latest message, the `assistant` message Claude just produced: any `text` blocks and one `tool_use` block per tool call the frame lists, in the order the model produced them. Earlier conversation is left out, because the prompt frame sent before that model call carried it. Read the last entry of `messages`, because the protocol may later add earlier messages before it.
255* Each `tool_use` block carries a `tool_info` object that says who provides the tool.
256 
257Where `session_id` is set, it is the same on both frames. The tool call frame has its own `request_id`, which is opaque like the prompt frame's.
258 
259`tool_info` says who provides the tool, not who runs it or what it can reach. It is one of four kinds, told apart by its `type` field, and each kind carries its own fields. Anthropic sends the first of the following kinds that fits the tool. New kinds may appear: accept a `type` you don't recognize, and for such a kind rely only on `type`.
260 
261An optional field that doesn't apply is left out, never `null`, so a `tool_info` can be just `{"type": "client"}`. `tool_name` is chosen by whoever defined the tool, and a server's `toolset_name` by whoever wrote the request, so don't treat either as a trust boundary.
262 
263### Platform tools
264 
265A platform tool is one of the Claude API's predefined tools, such as web search or bash. It is `"platform"` whether Anthropic or the application that calls Claude runs it.
266 
267| Field | Present | Description |
268| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
269| `type` | Always | `"platform"` |
270| `tool_type` | Always | The tool's versioned type, such as `web_search_20250305`. Match it exactly; don't parse a name or a date out of it. |
271| `toolset_name` | Optional | The toolset the tool belongs to, such as `browser`. |
272 
273### Application tools
274 
275An application tool is one that the Anthropic application making the request provides itself, such as claude.ai's own tools. It is `"application"` whether Anthropic or the application that calls Claude runs it.
276 
277| Field | Present | Description |
278| -------------- | -------- | --------------------------------- |
279| `type` | Always | `"application"` |
280| `toolset_name` | Optional | The group of tools it belongs to. |
281 
282### Third-party tools
283 
284A third-party tool is one on a server that Anthropic knows of, such as a claude.ai connector or an MCP server that the request names in `mcp_servers`. This doesn't mean Anthropic has vetted the server.
285 
286| Field | Present | Description |
287| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
288| `type` | Always | `"third_party"` |
289| `toolset_name` | Optional | The name the request gives the server. |
290| `origin` | Optional | The scheme, host, and non-default port of the server's URL. An absent `origin` means unknown, not safe. |
291| `verified_origin` | Whenever `origin` is | `true` only when Anthropic's servers connect to the server themselves. Treat `false` as an origin that Anthropic hasn't confirmed. |
292 
293A `tool_use` block for a tool on an MCP server that the request names `crm` in `mcp_servers`:
294 
295```json
296{
297 "type": "tool_use",
298 "id": "toolu_01GhIjKlMnOpQrStUvWxYzAb",
299 "tool_name": "crm_search",
300 "input": {
301 "query": "accounts renewing in Q4"
302 },
303 "tool_info": {
304 "type": "third_party",
305 "toolset_name": "crm",
306 "origin": "https://mcp.crm.example.com",
307 "verified_origin": true
308 }
309}
310```
311 
312### Client tools
313 
314A client tool is any other tool. The application that calls Claude declares it and receives its calls. A call to a tool the request doesn't declare is also `"client"`.
315 
316| Field | Present | Description |
317| -------------- | -------- | --------------------------------- |
318| `type` | Always | `"client"` |
319| `toolset_name` | Optional | The group of tools it belongs to. |
320 
321A `tool_use` block for a tool that the calling application declares:
322 
323```json
324{
325 "type": "tool_use",
326 "id": "toolu_01AbCdEfGhIjKlMnOpQrStUv",
327 "tool_name": "read_file",
328 "input": {
329 "path": "reports/q3.txt"
330 },
331 "tool_info": {
332 "type": "client"
333 }
334}
335```
336 
247337## Return a verdict
248338 
249339Respond with HTTP 200 and a JSON verdict body for both outcomes; the `action` field discriminates. To allow the request:
from line 369
279369 
280370Anthropic reads at most 64 KiB of the response body, and the body must be uncompressed. Redirects are not followed, and cookies are ignored. Unknown fields in the verdict body are ignored, so you can return a richer object alongside the fields documented here.
281371 
372A tool call frame takes the same verdict body, and every rule in this section applies to it unchanged. `allow` lets the tool calls run and the response continues; `deny` stops all of them and ends the response with the same error as a denied prompt, including your `deny_reason`. Text delivered before the first tool call is not taken back.
373 
282374## Verify the signature
283375 
284376Requests are signed per the [Standard Webhooks](https://www.standardwebhooks.com/) specification, using three headers. Anthropic sends the header names in lowercase, and proxies are free to re-case them, so look them up case-insensitively.
from line 767
675767 
676768### Timeout and retry
677769 
678Your administrator sets a verdict timeout between 1 and 10,000ms (5,000ms by default). The budget covers the entire exchange: connection, TLS handshake, request, and response.
770Your administrator sets a verdict timeout between 1 and 10,000ms (5,000ms by default). The budget covers the entire exchange: connection, TLS handshake, request, and response. The same timeout applies to tool call frames.
679771 
680772Anthropic retries exactly once, after a 100ms delay, and only when the connection attempt fails. The retry shares the same timeout budget and carries the same `webhook-id` and the same signature. Once your AI security server has responded, the exchange is never retried.
681773 
from line 781
689781 
690782Starting 10 minutes after the trip, Anthropic checks whether your server has recovered: at most about once per minute it sends your server the same synthetic test request that **Test connection** sends (`source.application` is `config-test`), signed like any other request and carrying no user content. Respond to it normally. A valid verdict, allow or deny, resets the breaker and enforcement resumes; a webhook failure leaves the breaker tripped, and the checks continue. An administrator can also reset the breaker at any time, and administrator configuration changes stop the automatic checks; see [Circuit breaker](https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration#circuit-breaker).
691783 
784Prompt frames and tool call frames share one circuit breaker, and failures on either count toward it.
785 
692786Each trip is recorded as an `inference_hooks_circuit_breaker_tripped` activity in the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed), one activity per trip. While the breaker is tripped, no per-request Inference hooks activities are recorded, so the trip activity is the feed's only record of the tripped window.
693787 
694788### Latency
695789 
696Enforcement adds your AI security server's round trip to the latency of every governed request in your organization. Keep the verdict fast, and load-test your server before rolling it out to a large organization.
790Enforcement adds your AI security server's round trip to the latency of every governed request in your organization. With **Validate tool calls** on, a response that produces a tool call frame also waits for its verdict, in shadow mode as well. Keep the verdict fast, and load-test your server before rolling it out to a large organization.
697791 
698792### Source IP addresses
699793 
from line 797
703797 
704798The protocol grows without breaking correctly written servers. Your server must ignore:
705799 
706* Unknown top-level fields on the prompt frame.
800* Unknown top-level fields on either frame.
707801* Unknown keys in `metadata`.
708802* New `source.application` values.
709803* New `actor.type` values. `actor` is a union discriminated on `type`, and `"user"` is the only kind sent today; a future kind guarantees only that `type` is present.
Feedback