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

# Client Events

Client events are JSON messages sent on the Streaming World WSS control connection. Use `event.create` to guide what happens next, `event.cancel` to cancel guidance that has not yet been applied, and Session events to control whether the world advances.

<Note>
  **One open-ended Event.** Keep dialogue, behavior, reactions, movement, ambience, and presentation together in natural language. The API does not expose separate speakers, lines, actions, beats, scenes, shots, tracks, or state patches.
</Note>

<h2 id="streaming-world-client-envelope">
  Common event envelope
</h2>

Every client message has a client-generated `event_id` and a `type`. A successful WebSocket write only means the message left your process. Wait for the corresponding server event before treating the request as accepted or effective.

<ResponseField name={"event_id"} type={"string"}>
  A non-empty id generated by the client and unique within the Session. Reuse it when retrying the same message after an uncertain delivery result.
</ResponseField>

<ResponseField name={"type"} type={"string"}>
  One of `event.create`, `event.cancel`, `session.hold`, or `session.resume`.
</ResponseField>

<Note>
  **Two different ids.** The envelope `event_id` identifies this client message. The `world_event_id` returned by `event.accepted` identifies the open-ended Event inside the world. Use the latter in later lifecycle messages and cancellation requests.
</Note>

<Note>
  **Idempotent retries.** Repeating the same `event_id` with the same payload does not apply the request twice and returns the original disposition. Reusing an id with a different payload returns `idempotency_conflict`.
</Note>

<Note>
  **Forward compatibility.** Ignore server event types and fields you do not recognize. Unknown client event types and unsupported enum values return an `error` event.
</Note>

* **Event**: [`event.create`](#event-world-event-create), [`event.cancel`](#event-world-event-cancel)
* **Session**: [`session.hold`](#event-world-session-hold), [`session.resume`](#event-world-session-resume)

<h3 id="world-client-world-events">
  World Events
</h3>

<h3 id="event-world-event-create">
  event.create
</h3>

Creates one open-ended Event that steers the unpublished future of the running world. Its ordered content blocks may select named References and describe a multi-character or environmental development as one coherent intent. The entire Event is validated atomically.

The server first responds with `event.accepted` and a `world_event_id`. Later `event.applied` reports when the first influenced media enters the outgoing path. An accepted Event is not necessarily visible yet, and an applied Event is not semantically complete.

<ResponseField name={"event_id"} type={"string"}>
  Client-generated message id used for correlation and idempotent retries.
</ResponseField>

<ResponseField name={"type"} type={"\"event.create\""}>
  Must be `event.create`.
</ResponseField>

<ResponseField name={"event"} type={"object"}>
  The open-ended guidance to apply to the world.

  <Expandable title="properties">
    <ResponseField name={"content"} type={"array"}>
      One or more ordered content blocks. Every block must be listed in capabilities.event\_content\_types. If one block is invalid or unsupported, no world Event is created.

      <Expandable title="properties">
        <ResponseField name={"input_text"} type={"object"}>
          Natural-language guidance for what should happen next.

          <Expandable title="properties">
            <ResponseField name={"type"} type={"\"input_text\""}>
              Must be `input_text`.
            </ResponseField>

            <ResponseField name={"text"} type={"string"}>
              A non-empty instruction. It can describe several participants and an extended interaction without assigning individual lines or actions.
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name={"input_reference"} type={"object"}>
          Selects a named Reference declared at Session creation. A Reference is a conditioning anchor, not an entity or mutable world-state record.

          <Expandable title="properties">
            <ResponseField name={"type"} type={"\"input_reference\""}>
              Must be `input_reference`.
            </ResponseField>

            <ResponseField name={"name"} type={"string"}>
              The exact name of an immutable Session Reference, such as `A` or `hotel_lobby`.
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name={"input_image"} type={"capability-gated object"}>
          A runtime image input. Use it only when `input_image` is listed in `capabilities.event_content_types`.

          <Expandable title="properties">
            <ResponseField name={"type"} type={"\"input_image\""}>
              Must be `input_image`.
            </ResponseField>

            <ResponseField name={"url"} type={"string"}>
              An HTTPS URL for an image directly fetchable by Vivix.
            </ResponseField>

            <ResponseField name={"mime_type"} type={"optional string"}>
              Image MIME type, such as `image/jpeg` or `image/png`.
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name={"input_audio"} type={"capability-gated object"}>
          A runtime audio input. Use it only when `input_audio` is listed in `capabilities.event_content_types`.

          <Expandable title="properties">
            <ResponseField name={"type"} type={"\"input_audio\""}>
              Must be `input_audio`.
            </ResponseField>

            <ResponseField name={"url"} type={"string"}>
              An HTTPS URL for an audio file directly fetchable by Vivix.
            </ResponseField>

            <ResponseField name={"mime_type"} type={"optional string"}>
              Audio MIME type, such as `audio/wav` or `audio/mpeg`.
            </ResponseField>

            <ResponseField name={"transcript"} type={"optional string"}>
              A caller-supplied transcript that helps interpret speech in the audio.
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name={"handling"} type={"\"steer\""}>
      Must be `steer`. Vivix preserves committed media, prepares a coherent continuation, and redirects unpublished future media at a safe boundary. The value must also appear in `capabilities.event_handling`.
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  **No queue or rollback.** There is no enqueue or after-current mode because an open-ended Event has no reliable completion boundary. Steer does not retract media that is already committed, published, or buffered, and it does not promise a frame-accurate cut.
</Note>

```json event.create theme={null}
{
  "event_id": "evt_world_020",
  "type": "event.create",
  "event": {
    "content": [
      { "type": "input_reference", "name": "A" },
      { "type": "input_reference", "name": "B" },
      {
        "type": "input_text",
        "text": "A notices that B keeps one hand hidden below the counter and begins to test his story. B first pretends not to understand, then accidentally reveals too much. Let the exchange develop naturally. Preserve both characters’ identities, voices, positions, and prior experience."
      }
    ],
    "handling": "steer"
  }
}
```

<h3 id="event-world-event-cancel">
  event.cancel
</h3>

Cancels an accepted world Event before it becomes effective. Send this event only when `capabilities.event_cancel` is `true`. The server confirms success with `event.cancelled`.

<Note>
  **Cancellation is not undo.** After `event.applied`, the Event has already entered media history and cannot be cancelled. Send a newer Event to redirect what happens next.
</Note>

<ResponseField name={"event_id"} type={"string"}>
  Client-generated message id used for correlation and idempotent retries.
</ResponseField>

<ResponseField name={"type"} type={"\"event.cancel\""}>
  Must be `event.cancel`.
</ResponseField>

<ResponseField name={"world_event_id"} type={"string"}>
  The domain Event id returned by `event.accepted`. If it has already been applied when this request is processed, the server returns `event_not_cancelable`.
</ResponseField>

```json event.cancel theme={null}
{
  "event_id": "evt_cancel_world_020",
  "type": "event.cancel",
  "world_event_id": "world_event_020"
}
```

<h3 id="world-client-session-events">
  Session Events
</h3>

<h3 id="event-world-session-hold">
  session.hold
</h3>

Requests that the world stop advancing at a safe media boundary while preserving the Session and its continuity. The server reports the effective result with `media.state.updated` where `state` is `held` and `request_event_id` matches this client message.

A hold may allow already committed media to finish. It retains the last available visual output and does not erase prior Event influence.

<ResponseField name={"event_id"} type={"string"}>
  Client-generated message id used for correlation and idempotent retries.
</ResponseField>

<ResponseField name={"type"} type={"\"session.hold\""}>
  Must be `session.hold`.
</ResponseField>

```json session.hold theme={null}
{
  "event_id": "evt_session_hold_001",
  "type": "session.hold"
}
```

<h3 id="event-world-session-resume">
  session.resume
</h3>

Requests that a held Session continue from its existing continuity. The server reports the effective result with `media.state.updated` where `state` is `running` and `request_event_id` matches this client message. Creating a new world Event while held also requests an implicit resume.

<ResponseField name={"event_id"} type={"string"}>
  Client-generated message id used for correlation and idempotent retries.
</ResponseField>

<ResponseField name={"type"} type={"\"session.resume\""}>
  Must be `session.resume`.
</ResponseField>

```json session.resume theme={null}
{
  "event_id": "evt_session_resume_001",
  "type": "session.resume"
}
```

<h2 id="streaming-world-client-errors">
  Request errors
</h2>

A request rejected before admission produces an `error` server event with the triggering `request_event_id`. An Event that was accepted but cannot later be applied produces `event.failed` instead.

| Code | Meaning |
| - | - |
| `invalid_request` | The JSON shape, required fields, or field values are invalid. |
| `unsupported_event_content` | At least one content block is not supported by this Session. |
| `unsupported_event_handling` | The requested handling value is not advertised by this Session. |
| `reference_not_found` | An input\_reference name does not exist in this Session. |
| `world_event_not_found` | The cancellation target does not exist in this Session. |
| `event_not_cancelable` | Cancellation is unsupported or the world Event has already been applied. |
| `session_not_ready` / `session_closed` | The Session cannot accept the requested control message in its current lifecycle state. |
| `idempotency_conflict` | The same client event\_id was reused with a different payload. |
