Skip to content
WP EngineDocumentation

List events

GET
/v1/sessions/{session_id}/events
<?php
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://api.ai.wpengine.com/v1/sessions/example/events?limit=20&order=asc&include_thinking=false', [
'headers' => [
'Authorization' => 'Bearer <token>',
],
]);
echo $response->getBody();

Returns events for a session, ordered by created_at. Pagination is keyset-based using the opaque page cursor. In addition to the events you sent, the list includes events produced by the agent as it responds: agent.message replies, agent.tool_use / user.tool_result pairs when the agent uses tools, and session status events (session.status_running, session.status_idle, session.error). Poll this endpoint after sending a user.message to retrieve the agent’s reply; a session.status_idle event marks the end of the turn. A session.status_idle event whose content carries stop_reason: client_tool_use means the run has paused waiting for the client to execute one or more tools — resume it by sending a user.tool_result for each pending tool_use_id (listed in that same event’s tool_use_ids array). session.status_idle and session.error events also carry a usage object reporting the tokens and credits consumed by the run cycle that produced them, and the run reports each kept turn’s tokens as it completes, as a session.turn_usage event — so a client polling mid-run can follow consumption turn by turn instead of waiting for the run to end. The cycle’s charge remains the usage object on session.status_idle or session.error. A client that also holds an open GET /v1beta1/sessions/{session_id}/events/stream connection (which delivers only events produced after it opens; see that endpoint’s description) can use the after_id parameter here to backfill anything it missed — on first connect, after a disconnect, or across a server-initiated rotation — with the id of the last event it already has, in place of the opaque page cursor; after_id and page are mutually exclusive. 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.

limit
integer
default: 20 >= 1 <= 100

Maximum events per page (default 20, max 100).

order
string
default: asc
Allowed values: asc desc

Sort direction by created_at (default asc).

page
string

Opaque cursor from previous next_page field. Mutually exclusive with after_id.

after_id
string

List events strictly after this durable event id, in the direction given by order (default asc, the typical case for backfilling a reconnecting client that already knows the last event it has, e.g. from the event stream) — a named alternative to paging with an opaque cursor. Must reference an event belonging to this session — an unrecognized or foreign id is rejected with 400. Mutually exclusive with page.

include_thinking
boolean

When true, agent.message events keep their thought blocks — the model’s reasoning, produced when the agent runs with reasoning_effort set. Each thought block has type “thought”, a text field holding the reasoning summary, and may carry 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. Defaults to false, in which case thought blocks are omitted from event content entirely.

List of events

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
next_page

Opaque cursor for next page.

string
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 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"
}
}

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"
}
}