> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aui.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Events Webhook

> Trigger your agent from your own systems by POSTing an event — processed asynchronously.

The events webhook lets your own systems — ticketing platforms, CRMs, internal
services — trigger your agent. You POST an event, Apollo queues it, and the
agent runs on it in the background.

1. Your system sends `POST /messaging/v1/events` with a JSON body.
2. Apollo validates the body, resolves the agent bound to your agent API key,
   and durably queues the event.
3. Apollo responds `202 Accepted` with an `event_id`.

<Note>
  The agent runs **asynchronously**. A `202` confirms the event was queued —
  not that the agent has finished, or even started, processing it.
</Note>

***

## Send an event

```bash cURL theme={"dark"}
curl -X POST "https://api-v3.aui.io/apollo-api/messaging/v1/events" \
  -H "Content-Type: application/json" \
  -H "x-agent-api-key: <agent_api_key>" \
  -d '{
    "thread_id": "ticket-11115",
    "agent_variables": {
      "ticket.id": "11115",
      "ticket.requester_email": "customer@example.com",
      "ticket.channel": "web",
      "ticket.human_has_replied": false
    }
  }'
```

### POST `/messaging/v1/events`

#### Authentication

<ParamField header="x-agent-api-key" type="string" required>
  Your agent API key (`sk-...`). The key is bound to a single agent — events
  are always delivered to that agent, so the body never carries an agent id.
</ParamField>

<Warning>
  Keep the agent API key secret. Use it only from your servers, never in
  browsers or mobile apps, and rotate it if it is exposed.
</Warning>

#### Request body

Provide `text`, `agent_variables`, or both as the agent's input.

<ParamField body="text" type="string">
  The message to run the agent on. When omitted, the agent runs on
  `agent_variables` alone.
</ParamField>

<ParamField body="agent_variables" type="object" default="{}">
  Free-form key/value data passed to the agent as variables for this event.
  Values may be any JSON type.
</ParamField>

<ParamField body="thread_id" type="string">
  Your own id for the conversation this event belongs to — any string from 1
  to 255 characters. Reuse the same value to continue a conversation; omit it
  (or send a blank value) to start a new one. Unique per agent. Leading and
  trailing whitespace is trimmed.
</ParamField>

#### Response

<ResponseField name="event_id" type="string" required>
  Unique id assigned to this event. Include it when contacting support.
</ResponseField>

<ResponseExample>
  ```json 202 theme={"dark"}
  {
    "event_id": "7d4f0c7e-2b0a-4a8e-9a57-3f1c2a6a9e11"
  }
  ```
</ResponseExample>

***

## Conversations

`thread_id` groups events into a conversation. It is **your own** identifier —
a ticket id, chat id, or order id — not one Apollo issues.

<CodeGroup>
  ```json Start a new conversation theme={"dark"}
  {
    "text": "A customer asked for a refund on order 10482.",
    "agent_variables": {
      "customer_email": "jane@example.com",
      "order_id": "10482"
    }
  }
  ```

  ```json Continue a conversation theme={"dark"}
  {
    "thread_id": "zendesk-ticket-88231",
    "text": "The customer replied with a photo of the damaged item."
  }
  ```
</CodeGroup>

Events that share a `thread_id` are processed in the order they were accepted.

## Payload

Only `text`, `agent_variables`, and `thread_id` reach the agent. Any other
top-level fields are accepted but **ignored**. That means you can point an
existing third-party webhook at this URL without it being rejected — just put
everything the agent needs inside `agent_variables`.

The request body is limited to **1 MiB**.

***

## Errors

Failures use the standard [error envelope](/api/errors). Branch on
`error.code` and keep a default branch — the set may grow.

| HTTP status | Code                          | When                                                                                 |
| ----------- | ----------------------------- | ------------------------------------------------------------------------------------ |
| `400`       | `bad_request`                 | The request is malformed or missing required context.                                |
| `401`       | `unauthorized`                | The `x-agent-api-key` header is missing, or the key is invalid or revoked.           |
| `403`       | `forbidden`                   | The API key is not allowed to trigger this agent.                                    |
| `404`       | `not_found`                   | The agent bound to the API key no longer exists.                                     |
| `404`       | `webhooks.no_active_version`  | The agent has no published version — publish one first.                              |
| `404`       | `webhooks.no_runtime_version` | The agent's active version must be republished before it can receive events.         |
| `413`       | `webhooks.payload_too_large`  | The body exceeds the 1 MiB limit.                                                    |
| `422`       | `validation_error`            | The body is not valid JSON, or a field has the wrong type or length — see `details`. |
| `500`       | `internal_error`              | Unexpected server error. The event may not have been queued.                         |
| `502`       | `upstream_unavailable`        | The event could not be queued.                                                       |
| `503`       | `internal_error`              | Event ingestion is temporarily unavailable.                                          |

```json 422 theme={"dark"}
{
  "error": {
    "code": "validation_error",
    "message": "Validation failed",
    "request_id": "4f9a1c2e8b7d4e0f",
    "details": [
      { "field": "body.thread_id", "message": "String should have at most 255 characters" }
    ]
  }
}
```

## Retries

`502` and `503` responses mean the event was **not** queued. They are safe to
retry with backoff.

`4xx` responses won't succeed unchanged. Fix the request or the agent
configuration before sending again.
