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

# Messages

> Message requests with sync, streaming, and async patterns.

<Warning>
  **Upcoming release — Zylon 1.58**

  These docs are published ahead of release so you can prepare your API integrations. The release image is not yet available. For installations running 1.57, use the [1.57 documentation](/en/v1.57/overview).
</Warning>

Messages is the core of ZylonGPT. You send a conversation history, and Zylon returns the next assistant message as a **list of content blocks** (text, tool calls, tool results, and more).

## Prerequisites

* An API token. See [Backoffice Developer Console](/en/v1.58/developer-manual/get-started/developer-console).
* Your Zylon hostname (replace `{BASE_URL}` in the examples).

`PrivateGPT.Read.All` permits synchronous `POST /messages`, `POST /messages/validate`, and the other endpoints in the [ZylonGPT read-only allowlist](/en/v1.58/developer-manual/build-with-zylon/zylon-gpt-api/overview). `Read.All` permits the same calls only when the account token carries `gateway_id`; without gateway context, it cannot call ZylonGPT. Effective access also depends on the token owner's role permissions.

## Basic request and response

Send one user message and get back one assistant message.

<Tabs>
  <Tab title="Single message">
    ```bash theme={null}
    curl -X POST "https://{BASE_URL}/api/gpt/v1/messages" \
      -H "Authorization: Bearer {API_TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "default",
        "max_tokens": 32,
        "temperature": 0,
        "messages": [
          { "role": "user", "content": "Write a one-sentence status update about deploying a billing dashboard and fixing three bugs." }
        ]
      }'
    ```
  </Tab>

  <Tab title="Content blocks">
    ```bash theme={null}
    curl -X POST "https://{BASE_URL}/api/gpt/v1/messages" \
      -H "Authorization: Bearer {API_TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "default",
        "max_tokens": 32,
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": [
              { "type": "text", "text": "Write a one-sentence status update about deploying a billing dashboard and fixing three bugs." }
            ]
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

<Accordion title="Example response">
  ```json theme={null}
  {
    "id": "msg_abf981cf3f1c449eacb7a85c064ca505",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "text",
        "start_timestamp": "2026-02-06T13:23:16.876744Z",
        "stop_timestamp": "2026-02-06T13:23:16.975362Z",
        "text": "Deployed the new billing dashboard and resolved three bugs successfully."
      }
    ],
    "model": "private-gpt",
    "stop_reason": "end_turn",
    "usage": {
      "input_tokens": 95,
      "output_tokens": 16
    }
  }
  ```
</Accordion>

To render plain text, concatenate the `text` values from any blocks where `type` is `"text"`.

## Messages shape

The same message body is used by ZylonGPT and by the `pgpt` field in Workspace chat/interaction requests. Send conversation content; the selected model or gateway determines which optional settings it supports. `model` and `max_tokens` are nullable options, rather than universally required fields. Keeping them explicit makes model selection and output limits predictable; validate requests against your gateway.

<Accordion title="Request body">
  | Field | Type / default | Description |
  | - | - | - |
  | `messages` | message\[]; `[]` | Conversation history. Each message has `role` (`user` or `assistant`) and `content` (string or content-block array). Workspace interaction creation requires exactly one user message. |
  | `model` | string or null | Model name, commonly `default`; validate omission against the selected gateway. |
  | `max_tokens` | integer or null | Output token limit, subject to model validation. |
  | `stream` | boolean; `false` | ZylonGPT Messages returns JSON by default and SSE when `true`. Current `/app/chat` and Workspace interaction routes stream regardless of this flag. |
  | `system` | string, object, object\[], or null | System text and configuration; nested fields below. |
  | `tools` | object\[] or null | Tool definitions. See [Tools](/en/v1.58/developer-manual/build-with-zylon/tools/introduction-to-tools). |
  | `tool_choice` | object or null | Tool selection and validation settings below. |
  | `tool_context` | object\[] or null | Typed context, such as `ingested_artifact` or `sql_database`; see the relevant tool guide. |
  | `mcp_servers` | object\[] or null | MCP server configurations. Each requires `url`; `name` and `tool_configuration` are optional. |
  | `thinking` | object or null | `enabled` defaults to `false`; `type` (string) and `budget_tokens` (integer) are optional. |
  | `output_config` | object or null | `effort`: `low`, `medium`, `high`, or `max`; optional `format` described below. |
  | `cache_control` | object or null | When supplied, requires string `type`. Support depends on the model. |
  | `temperature`, `min_p`, `top_p` | number or null | Sampling options; supported ranges depend on the model. |
  | `top_k` | integer or null | Sampling option. |
  | `repetition_penalty`, `presence_penalty`, `frequency_penalty` | number or null | Token penalty options. |
  | `seed` | integer or null | Optional sampling seed. |
  | `priority` | integer or null | Optional request priority. |
  | `stop_sequences` | string\[]; `[]` | Custom generation boundaries. |
  | `metadata` | object; `{}` | Optional nullable string `ws_member_id`. Use a workspace-member ID, not an account ID. `user_id` remains an input alias; send only one name. |
  | `service_tier` | string; `auto` | `auto` or `standard_only`. |
  | `inference_geo` | string or null | Optional inference location preference. |
  | `container` | string or null | Optional existing container identifier. |
  | `message_id`, `correlation_id` | string or null | Optional message and correlation identifiers. |

  Nullable fields can be omitted. A non-nullable option with a default can be omitted but should not be sent as `null`.
</Accordion>

<Accordion title="System, tool choice, and structured output">
  | Object | Field | Type / default |
  | - | - | - |
  | `system` | `text` | Optional string. |
  | `system` | `citations` | Object; `enabled` defaults to `false`, `known_citations` is an optional citation array. |
  | `system` | `blob_visibility` | Optional `binary`, `internal`, or `public`. |
  | `system` | `extensions` | Optional string\[]; currently supports `zylon`. |
  | `system` | `prompt` | Object with boolean `tools`, `citations`, `thinking`, `code_execution`, and `skills`; each defaults to `false`. |
  | `tool_choice` | `type` | String; `auto`. |
  | `tool_choice` | `name` | Optional string identifying a tool. |
  | `tool_choice` | `disable_parallel_tool_use` | Boolean; `false`. |
  | `tool_choice` | `validation_mode` | `eager` or `lazy`; `lazy`. |
  | `output_config.format` | `type` | Required `json_schema`. |
  | `output_config.format` | `schema` | Required JSON Schema object. |

  `response_format` is deprecated; use `output_config.format`. Move deprecated `thinking.effort` to `output_config.effort`. Replace `system.use_default_prompt` with the individual `system.prompt` flags; setting the old flag to `true` enables all prompt categories.
</Accordion>

<Accordion title="Message response fields">
  | Field | Type | Meaning |
  | - | - | - |
  | `id`, `type`, `role`, `model` | string | Message identity, `message` type, `assistant` role, and selected model. |
  | `created` | integer | Epoch milliseconds. |
  | `content` | object\[] | Content blocks. See the [1.58 server tool blocks](/en/v1.58/developer-manual/build-with-zylon/workspace-api/api-migration-1-57-to-1-58#server-tool-content-blocks). |
  | `stop_reason` | string or null | `end_turn`, `max_tokens`, `stop_sequence`, `tool_use`, `pause_turn`, or `refusal`. |
  | `interaction_stop_reason` | string or null | Overall interaction outcome: `stop`, `error`, `cancelled`, or `refusal`. |
  | `stop_details` | object or null | Required `type`, optional `category` and `explanation`. |
  | `container` | object or null | Required `id`, optional `expires_at` string. |
  | `usage` | object | `input_tokens` and `output_tokens` (default `0`); optional cache and server-tool usage below. |
  | `errors` | object\[] | Error details when available. |

  `usage` may include `cache_creation_input_tokens`, `cache_read_input_tokens`, `inference_geo`, `service_tier`, `cache_creation` (`ephemeral_1m_input_tokens`, `ephemeral_1h_input_tokens`, `ephemeral_5m_input_tokens`), and `server_tool_use` (`web_fetch_requests`, `web_search_requests`). Counts in the nested usage objects default to `0`. Nullable response fields may be omitted. There is no top-level `stop_sequence` field; use `stop_reason: "stop_sequence"`. See [Handling stop reasons](/en/v1.58/developer-manual/build-with-zylon/zylon-gpt-api/handling-stop-reasons).
</Accordion>

## Validate a request

Use `/messages/validate` to check payload shape before sending a real request. It returns `valid: true` or a list of validation errors.

```bash theme={null}
curl -X POST "https://{BASE_URL}/api/gpt/v1/messages/validate" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "default",
    "max_tokens": 32,
    "messages": [
      { "role": "user", "content": "Validate this payload." }
    ]
  }'
```

Example response:

```json theme={null}
{ "valid": true, "errors": null }
```

## Multi-turn conversations

To continue a conversation, include the prior turns in `messages`:

```bash theme={null}
curl -X POST "https://{BASE_URL}/api/gpt/v1/messages" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "default",
    "max_tokens": 16,
    "temperature": 0,
    "messages": [
      { "role": "user", "content": "My name is Ada." },
      { "role": "assistant", "content": "Nice to meet you." },
      { "role": "user", "content": "What is my name? Reply with only the name, no punctuation." }
    ]
  }'
```

<Accordion title="Example response">
  ```json theme={null}
  {
    "id": "msg_9b14c8fd514741d29a0dff8996ca9213",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "text",
        "start_timestamp": "2026-02-06T10:34:12.924887Z",
        "stop_timestamp": "2026-02-06T10:34:12.974785Z",
        "text": "Ada"
      }
    ],
    "model": "private-gpt",
    "stop_reason": "end_turn",
    "usage": { "input_tokens": 135, "output_tokens": 2 }
  }
  ```
</Accordion>

## System prompts

Use the top-level `system` field to control assistant behavior (instead of a `"system"` role message):

<Callout type="tip">
  Prefer the top-level <code>system</code> field for system instructions so they are applied consistently across the whole request.
</Callout>

```bash theme={null}
curl -X POST "https://{BASE_URL}/api/gpt/v1/messages" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "default",
    "max_tokens": 8,
    "temperature": 0,
    "system": { "text": "You are a support agent. Reply with only a short ticket title." },
    "messages": [
      { "role": "user", "content": "The login button on mobile does not work." }
    ]
  }'
```

<Accordion title="Example response">
  ```json theme={null}
  {
    "id": "msg_4e328dc4baeb42b8a18dc0c4abd89468",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "text",
        "start_timestamp": "2026-02-06T13:37:36.368426Z",
        "stop_timestamp": "2026-02-06T13:37:36.446733Z",
        "text": "Mobile login button not working"
      }
    ],
    "model": "private-gpt",
    "stop_reason": "end_turn",
    "usage": { "input_tokens": 100, "output_tokens": 6 }
  }
  ```
</Accordion>

## Structured JSON output (json\_schema)

If you need machine-readable output, set `output_config.format.type` to `json_schema` and provide `output_config.format.schema`. Zylon returns JSON as text in a `text` content block.

```bash theme={null}
curl -X POST "https://{BASE_URL}/api/gpt/v1/messages" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "default",
    "max_tokens": 128,
    "system": {
      "text": "Return ONLY valid JSON."
    },
    "messages": [
      {
        "role": "user",
        "content": "We deployed the billing dashboard. Return a status and the next step."
      }
    ],
    "output_config": {
      "format": {
        "type": "json_schema",
        "schema": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "status": {
              "type": "string"
            },
            "next_step": {
              "type": "string"
            }
          },
          "required": [
            "status",
            "next_step"
          ]
        }
      }
    }
  }'
```

<Accordion title="Example response">
  ```json theme={null}
  {
    "id": "msg_eaf35004b4654234be5e767ea09e72e6",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "text",
        "start_timestamp": "2026-02-06T13:39:44.864978Z",
        "stop_timestamp": "2026-02-06T13:39:45.412991Z",
        "text": "{\"status\":\"success\",\"next_step\":\"Monitor adoption and collect feedback.\"}"
      }
    ],
    "model": "private-gpt",
    "stop_reason": "end_turn",
    "usage": { "input_tokens": 98, "output_tokens": 16 }
  }
  ```
</Accordion>

## Streaming (SSE)

Set `stream: true` to receive a `text/event-stream` response containing events like `content_block_delta` (token deltas).

```bash theme={null}
curl -N -X POST "https://{BASE_URL}/api/gpt/v1/messages" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "model": "default",
    "stream": true,
    "max_tokens": 32,
    "messages": [
      { "role": "user", "content": "Give a three-word tagline for a productivity app." }
    ]
  }'
```

<Accordion title="Example streamed events">
  ```text theme={null}
  event: message_start
  data: {"type":"message_start","message":{"id":"msg_b55d29718361410bad4f80f8f67c6b72","type":"message","role":"assistant","content":[],"model":"private-gpt","usage":{}}}

  event: content_block_start
  data: {"type":"content_block_start","index":0,"block_id":"block_019c331ac11375cea03f7e0fb7a2a044","content_block":{"type":"text","start_timestamp":"2026-02-06T13:18:37.331257Z","text":""}}

  event: content_block_delta
  data: {"type":"content_block_delta","index":0,"block_id":"block_019c331ac11375cea03f7e0fb7a2a044","delta":{"type":"text_delta","text":"Focus"}}

  event: content_block_delta
  data: {"type":"content_block_delta","index":0,"block_id":"block_019c331ac11375cea03f7e0fb7a2a044","delta":{"type":"text_delta","text":" fast daily"}}

  event: content_block_stop
  data: {"type":"content_block_stop","stop_timestamp":"2026-02-06T13:18:37.417617Z","index":0,"block_id":"block_019c331ac11375cea03f7e0fb7a2a044"}

  event: message_delta
  data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"input_tokens":90,"output_tokens":3}}

  event: message_stop
  data: {"type":"message_stop"}
  ```
</Accordion>

## Async messages

<Warning>
  Async message start, stream, status, cancel, and delete routes require `PrivateGPT.ReadWrite.All` or `ReadWrite.All`. Read-only tokens receive `403` for every async lifecycle route.
</Warning>

Async messages use the **same request body** as sync messages—you just call a different endpoint. The main difference is the **response shape**: sync returns a full message, async returns a `message_id` you can stream or poll later.

<Accordion title="Sync vs async response shape">
  <Tabs>
    <Tab title="Sync response">
      ```json theme={null}
      {
        "id": "msg_abf981cf3f1c449eacb7a85c064ca505",
        "type": "message",
        "role": "assistant",
        "content": [
          {
            "type": "text",
            "start_timestamp": "2026-02-06T13:23:16.876744Z",
            "stop_timestamp": "2026-02-06T13:23:16.975362Z",
            "text": "Deployed the new billing dashboard and resolved three bugs successfully."
          }
        ],
        "model": "private-gpt",
        "stop_reason": "end_turn",
        "usage": {
          "input_tokens": 95,
          "output_tokens": 16
        }
      }
      ```
    </Tab>

    <Tab title="Async response">
      ```json theme={null}
      {
        "message_id": "1cc8ed5e-fc7a-45e1-baf4-0b916ed32290",
        "status": "pending",
        "message": "Request initiated successfully"
      }
      ```
    </Tab>
  </Tabs>
</Accordion>

### Start an async message

```bash theme={null}
curl -X POST "https://{BASE_URL}/api/gpt/v1/messages/async" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "default",
    "max_tokens": 32,
    "messages": [
      { "role": "user", "content": "Say only: async ok" }
    ]
  }'
```

### Stream or poll status

Stream events:

```bash theme={null}
curl -N "https://{BASE_URL}/api/gpt/v1/messages/async/{message_id}/stream" \
  -H "Authorization: Bearer {API_TOKEN}" \
  -H "Accept: text/event-stream"
```

Poll status:

```bash theme={null}
curl "https://{BASE_URL}/api/gpt/v1/messages/async/{message_id}/status" \
  -H "Authorization: Bearer {API_TOKEN}"
```

### Cancel or delete

* Cancel: `POST /messages/async/{message_id}/cancel`
* Delete: `DELETE /messages/async/{message_id}/delete`

## Common mistakes

* **Wrong method**: `/messages` is `POST`, not `GET`.
* **Missing auth header**: include `Authorization: Bearer ...`.
* **Wrong base URL**: use `https://{BASE_URL}/api/gpt/v1/`.
* **Invalid request body**: use `POST /messages/validate` to catch schema mistakes early.
* **Unexpected stops or errors**: see [Handling stop reasons](/en/v1.58/developer-manual/build-with-zylon/zylon-gpt-api/handling-stop-reasons) for causes and fixes.

## Next steps

<CardGroup cols={2}>
  <Card title="Tools" icon="toolbox" href="/en/v1.58/developer-manual/build-with-zylon/tools/introduction-to-tools">
    Let Zylon use built-in and custom tools during a message.
  </Card>

  <Card title="Artifacts" icon="file" href="/en/v1.58/developer-manual/build-with-zylon/working-with-artifacts">
    Ingest text, files, or URIs into collections for retrieval.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.