Skip to content
WP EngineDocumentation

Send events

POST
/v1/sessions/{session_id}/events
<?php
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://api.ai.wpengine.com/v1/sessions/example/events', [
'body' => '{ "events": [ { "type": "user.message", "content": [ { "type": "tool_result", "tool_use_id": "example", "content": "example", "is_error": true, "error_code": "example", "traceparent": "example", "client_timing": { "started_at_ms": 1, "ended_at_ms": 1 } } ] } ] }',
'headers' => [
'Authorization' => 'Bearer <token>',
'Content-Type' => 'application/json',
],
]);
echo $response->getBody();

Appends one or more events to a session and returns them with assigned ids. The processed_at timestamp is null until the event is processed by an agent run. Accepts user.message, system.message, and user.tool_result events, plus user.interrupt to stop a response in progress. A user.interrupt event may be sent by itself with content omitted or set to an empty array. It never starts a run. It requests cancellation of the exact run in flight when the event is accepted; if no run is in flight, the event is still appended and otherwise has no effect. Other runtime-control types (user.tool_confirmation, user.custom_tool_result, user.define_outcome) are rejected with 400. Sending a user.message starts the session’s agent running asynchronously; this response echoes the events persisted (which may include a synthetic cancellation; see below) and does not contain the agent’s reply. Retrieve the reply and status by listing events (GET /v1/sessions/{session_id}/events). A single request carries either user.tool_result events or a user.message/system.message, never both; mixing them is rejected with 400. While a run is in flight and the session is paused awaiting a client tool_result, a user.message or system.message is rejected with 400 — send the tool_result first. If no run holds the session, the message resolves the pause instead: the gateway prepends a synthetic user.tool_result with error_code “cancelled” for each outstanding tool_use, then persists your message, so a session whose client went away mid-tool can be continued. Submit tool_result promptly: a result submitted for a call that has already been cancelled is rejected with 409. Asynchronous agent execution is rolling out; until it is enabled for your site, this endpoint stores and echoes the submitted events without producing agent replies. Accepts a service-token bearer authenticating a site or an API key, either of which must be authorized for the session’s project, or a browser session token holding the session_events scope (bound to the session’s agent and, when the session records an owner_id, to that same visitor).

session_id
required
string

The session ID.

Media typeapplication/json
One of:
Message or tool-result events

Events to append to the session. A user.interrupt must be the only event in the request.

object
events
required
Array<object>
>= 1 items <= 100 items
object
type
required

Event type. user.message and system.message send text/document content. user.tool_result sends tool execution results for client tools the model called, resuming a paused run.

string
Allowed values: user.message system.message user.tool_result
content
required

Array of content blocks. For user.message and system.message, these are text/document blocks. For user.tool_result, each block is a tool_result object (see ToolResultBlock).

Array
>= 1 items
Any of:
object
type
required
string
Allowed values: tool_result
tool_use_id
required

The tool_use id this result answers.

string
content

Tool output as a string, or a JSON error envelope on failure. Optional; omitted when the client has nothing to report besides is_error.

is_error

True when the client tool call failed.

boolean
error_code

Machine-readable classification of a failure. Present only when is_error is true. One of invalid_input, permission_denied, not_found, tool_unavailable, declined, cancelled, rate_limited, timeout, unavailable, wp_fatal_error, execution_failed, or internal_error. cancelled is also what the gateway itself writes when a new message auto-resolves a stale pause. An unrecognised value is rejected with 400, as is an error_code on a block whose is_error is not true. Omitting error_code on a failure is accepted for backward compatibility; the failure is then counted as unclassified.

string
traceparent

W3C traceparent echoed from the matching session.status_idle tool_traceparents entry. Optional. Not returned in later event history.

string
client_timing
object
started_at_ms
required

Unix time in milliseconds when client-side execution started.

integer format: int64
ended_at_ms
required

Unix time in milliseconds when client-side execution ended.

integer format: int64

Events that were sent

Media typeapplication/json
object
data
required
Array<object>
object
id
required
string
type
required

Event type. Input events you send include user.message, system.message, user.tool_result, and user.interrupt. As the agent responds, the session also produces agent.message replies, agent.tool_use when the agent calls a tool, and status events: session.status_running, session.status_idle, and session.error. The session may also produce session.compaction events: when the conversation approaches the model’s context window, the oldest turns are summarized into a session.compaction event whose content is a single text block (the summary). Original events are retained; the summary only changes what the model is replayed on subsequent turns. Finally, each kept agentic-loop turn produces a session.turn_usage event reporting that turn’s token usage.

string
Allowed values: user.message user.tool_result user.interrupt system.message agent.message agent.tool_use session.status_running session.status_idle session.error session.compaction session.turn_usage
content
required

Array of content blocks. For user.message, system.message, and agent.message these are message content blocks (for example text, image, or document). For agent.tool_use the blocks are tool_use objects with type, id, name, and input fields. For user.tool_result they are tool_result objects with tool_use_id, content, and is_error; a failed one additionally carries error_code (the same bounded value as the event-level error_code field) and a content body holding a JSON error envelope — an object with a single “error” key whose value has code, message, an optional field naming the offending argument when exactly one is at fault, and retryable indicating whether repeating the identical call may succeed. Reading the envelope rather than the prose is what lets a consumer distinguish “correct this argument” from “try again in a moment”. A successful tool_result the gateway answered itself may instead carry status, currently only tool_loaded: the model named a tool that was declared on its agent but not yet in its tool list, so the tool was loaded and nothing was executed for that block. The model’s real call to the same tool follows on a later turn, so a consumer rendering a transcript can present the pair as loading that tool rather than as one call made twice. status is absent from every ordinary tool_result. For user.interrupt, content is an empty array. For session.status_idle the content carries a stop_reason: end_turn when the turn completed, max_iterations when the run hit its iteration limit, max_tokens when a turn hit its output-token limit (the agent.message may be truncated mid-content), model_context_window_exceeded when a turn stopped because the model’s context window filled up during generation, user_cancelled when a user.interrupt stopped the run, or client_tool_use when the run paused waiting for the client to execute a tool; when stop_reason is client_tool_use, the content also carries a tool_use_ids array listing the pending client tool call IDs. When stop_reason is client_tool_use, the content may also carry tool_traceparents: a map from each pending tool_use_id to a W3C traceparent the client can echo on tool_result for session trace correlation (optional; absent on older gateways). The content also carries context_tokens: the total token count (input + output) of the run’s most recent turn, reflecting the session’s current context footprint (since each turn resends the full history as input) — useful for warning a user before the conversation approaches the model’s context window. context_tokens is always present, including 0 when the cycle made no model request. It remains supported. The latest session.turn_usage event’s total_tokens is that last kept turn’s own footprint, with the rest of that turn’s usage alongside it, and is the better source for a new integration. After a cycle that compacted, idle context_tokens is the post-compaction estimate instead — the turn event is not rewritten. For session.turn_usage the content is a single block reporting one kept agentic-loop turn’s usage as that turn’s model request completed: turn (the turn’s position in the run, from 1), model (the model that served it), input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens, reasoning_tokens, total_tokens, and credits_nano. Providers do not separate tool-call and tool-result tokens from the prompt and completion counts, so neither does this shape. credits_nano here prices that kept request and is informational: a run cycle is charged once, and the charge is the credits_nano in the usage object on the cycle’s session.status_idle or session.error event. Summing the per-turn figures can differ from that charge by rounding and by tokens spent on a citation rescue retry that did not become a kept turn. For session.error the content carries a single block with type “error”, a client-safe text message, a machine-readable code: upstream_error (the model provider returned an error), rate_limit_error (the model provider is temporarily rate limited), context_exceeded (the conversation exceeded the model’s context window), upstream_timeout (the model provider took too long to respond), invalid_tool_schema (the model rejected a tool definition for this session; retrying the same model often fails), toolset_incomplete (the agent declares tools the gateway could not resolve — for example a knowledge_base collection that no longer exists; the run is stopped rather than continued with a partial toolset, and retrying will not help until the agent’s tools[] is corrected), run_timeout (the run’s overall time budget expired before the agent finished; send the message again, ideally as a smaller task), run_interrupted (the run was cut short before it finished; send the message again), run_abandoned (the run’s worker was lost before it finished and the run was settled afterwards; send the message again), or internal_error (an unexpected failure on our side); and an optional request_id correlating the failure with support-facing logs, present whenever one could be resolved for the request that triggered it. For session.compaction the content is a single text block (the summary) — original events are retained; the summary only changes what the model is replayed on subsequent turns. When the request passed include_thinking=true, an agent.message produced with reasoning_effort set may begin with a thought block: type “thought”, a text field holding the model’s reasoning summary, and optionally extra_content.gateway.thinking_ms — the measured reasoning duration in milliseconds. Models that reason without exposing the text yield thought blocks with an empty text field and only the duration metadata. Without include_thinking (the default), thought blocks are omitted from event content. On an agent.message reply grounded in a knowledge base, text blocks may carry a citations array listing KB source documents the model referenced. Each citation is an object with type (string discriminator — "knowledge_base" today; new source kinds may add values in the future), document_uri (string, the click-through URL) and document_title (string, the human-readable label). The array is present only when the reply referenced retrieved sources; absent otherwise. Consumers rendering a bottom-of-message Sources list should walk all text blocks, dedupe by document_uri, and render one link per unique source.

Array<object>
object
processed_at
string format: date-time
nullable
usage

Tokens and credits consumed by the run cycle that produced this event. Present only on session.status_idle and session.error — the two events every run cycle ends in — and reflects that run’s aggregated usage across all of its turns, including any usage billed before a mid-run failure. This is the charge for the run, including tokens spent on a citation rescue retry that is not listed on session.turn_usage. session.turn_usage reports each kept turn inside its content and never carries a usage object of its own, so counting this field across a session never double-counts.

object
input_tokens
required
integer
output_tokens
required
integer
cache_read_input_tokens
required
integer
cache_creation_input_tokens
required
integer
credits_nano
required

Billing total for this single run cycle, in nano-credits (billionths of a credit)

integer
error_code

Machine-readable classification of the failure this event reports, repeating at the event level the code its failing content block already carries — so a client can branch on the outcome without walking the blocks. Present only on an event that reports a failure: a session.error (where the value is the run-failure code from that event’s error block) or a user.tool_result whose tool_result block failed (where it is that block’s error_code). Absent on every successful event. When an event answers several tool calls and more than one failed, the first failing block’s code is reported. A failure that arrived without a code is reported as “unclassified”.

string
Allowed values: invalid_input permission_denied not_found tool_unavailable declined cancelled rate_limited timeout unavailable wp_fatal_error execution_failed internal_error unclassified upstream_error rate_limit_error context_exceeded upstream_timeout attachment_unsupported invalid_tool_schema insufficient_credits toolset_incomplete run_not_scheduled run_timeout run_interrupted run_abandoned
Example
{
"data": [
{
"type": "user.message",
"error_code": "invalid_input"
}
]
}

Invalid request body or parameters

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}

Missing or invalid bearer token

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}
WWW-Authenticate
string
Example
Bearer realm="ai-services"

The account’s credit balance is exhausted. Grant or top up credits before retrying. Distinct from 429, which is edge rate limiting.

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}

The token is valid, but the caller is not permitted to perform this action — either its scope/permission is insufficient or the authenticated user is not authorized for the target account (error type “permission_error”). On /v1/chat/completions specifically, a 403 with error type “content_policy_violation” instead means the request content was blocked by content moderation policy; that response never identifies which filter or category matched.

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}

The requested resource was not found

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}

Conflict. A tool_result was submitted for a tool_use that has already been cancelled, because a message resolved the pause it was holding. The session has moved on, so this is a benign late-arrival rather than a defect: discard the result and do not retry it.

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}

The server encountered an unexpected error while handling the request. Safe to retry once; if it persists, the cause is server-side and the request payload was not the problem.

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}

A required dependency is temporarily unavailable. Retry after a short delay with exponential back-off.

Media typeapplication/json
object
error
required
object
message
required
string
type
required
string
code
required
integer
request_id
required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string
Example
{
"error": {
"type": "invalid_request_error",
"request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
}
}