# Replace a chat's messages

`POST https://stylor.ai/api/v1/chat/update`

- Authentication: private API key, sent as `Authorization: Bearer sgpt-sk-…::…`
- Rate-limit resource: `api.v1.chat.update`
- Demo key: not accepted
- Deprecated: yes
- Web page: https://stylor.ai/guides/rest/v1/update-chat

> **Retired.** This endpoint answers `410 Gone` and no longer works.
> It is documented for reference only; use the v2 agent API's
> [Chat](https://stylor.ai/guides/rest/v2/agent-chat.md) instead.

Overwrite the **entire** message history of a chat with the array you
send. Use it to prune, correct or restructure a conversation; sending
`[]` empties the chat.

Unlike **Send a message**, no normalization is applied here: every
message must already be in a valid shape. In particular an
`output_status` part must be `resolved` or `needs_clarification`, and
every slot in an `output_slots` part needs a string `id`. Slots are also
checked against the stored slot rules on save (a `search` slot's
`query` must be 6–120 characters, `slot` and `fit` values must be
from their enums); a violation there is rejected with `422`
and a `details` array naming each offending path.

## Example request

```bash
curl -X POST "https://stylor.ai/api/v1/chat/update" \
  -H "Authorization: Bearer $STYLOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "chatId": "3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "I need a smart-casual outfit for a rooftop dinner."
        }
      ]
    },
    {
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "For a rooftop dinner I'\''d pair a silk slip dress with a cropped leather jacket."
        },
        {
          "type": "output_slots",
          "slots": [
            {
              "id": "8066a68a-a39e-4d3e-993a-3887f6245032",
              "type": "search",
              "slot": "dress",
              "query": "black silk slip dress",
              "filters": {
                "color_family": [
                  "black"
                ],
                "family": [
                  "dress"
                ],
                "exclude_terms": [],
                "boost_terms": [
                  "silk"
                ]
              },
              "results": []
            }
          ]
        },
        {
          "type": "output_status",
          "status": "resolved"
        }
      ]
    }
  ]
}'
```

## Request body

Content type `application/json`, required.

- `chatId` (string (uuid), required): Id of the chat to overwrite. [example `"3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88"`]
- `messages` (array<ChatMessage>, required): The complete new thread. May be empty. Not normalized — every message must already be valid.
  - `role` (string, required): Who wrote the message. `system` messages are passed to the model verbatim. [one of `"user"`, `"assistant"`, `"system"`; example `"user"`]
  - `content` (string | array<ChatMessageContentPart>, required): Plain text, or an array of content parts.
    - Option 1: string
    - Option 2: array<ChatMessageContentPart>
      - `type` (string, required): The kind of part. `input_*` parts are written by the shopper; `output_*` parts by the stylist. [one of `"input_text"`, `"input_image"`, `"output_text"`, `"output_slots"`, `"output_status"`]
      - `text` (string): The text. Required for `input_text` and `output_text`. [example `"I need a smart-casual outfit for a rooftop dinner."`]
      - `image_url` (string): Image reference for `input_image`. A public URL, a `data:` URI, or a Stylor image-delivery URL. [example `"https://example.com/inspiration.jpg"`]
      - `slots` (array<ChatSearchSlot | ChatOutfitCompositionsSlot>): The stylist's slots. Required for `output_slots`.
      - `status` (string): Outcome of the turn. Required for `output_status`. `needs_clarification` means the stylist asked a follow-up question and `slots` is empty. [one of `"resolved"`, `"needs_clarification"`]
      - `generating` (boolean): Server-managed, read-only. Present as `true` on the `output_status` part of an assistant message whose streamed reply is still in progress. Dropped from any message you send back in.

### Examples

#### Replace

Overwrite the chat with a new message history.

```json
{
  "chatId": "3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "I need a smart-casual outfit for a rooftop dinner."
        }
      ]
    },
    {
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "For a rooftop dinner I'd pair a silk slip dress with a cropped leather jacket."
        },
        {
          "type": "output_slots",
          "slots": [
            {
              "id": "8066a68a-a39e-4d3e-993a-3887f6245032",
              "type": "search",
              "slot": "dress",
              "query": "black silk slip dress",
              "filters": {
                "color_family": [
                  "black"
                ],
                "family": [
                  "dress"
                ],
                "exclude_terms": [],
                "boost_terms": [
                  "silk"
                ]
              },
              "results": []
            }
          ]
        },
        {
          "type": "output_status",
          "status": "resolved"
        }
      ]
    }
  ]
}
```

#### Clear

Empty the chat's messages.

```json
{
  "chatId": "3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88",
  "messages": []
}
```

## Responses

### 200

The messages were replaced.

Content type `application/json`:

- `chatId` (string (uuid), required): Id of the chat that was updated. [example `"3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88"`]
- `messagesCount` (integer, required): Number of messages now stored. [example `2`]

Example:

```json
{
  "chatId": "3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88",
  "messagesCount": 2
}
```

## Errors

Every error is a JSON object with an `error` string. Match on the status code; the message is written for people.

| Status | Message | When |
| --- | --- | --- |
| 400 | Request body must be valid JSON. | The request body could not be parsed as JSON. |
| 400 | Request body must be a JSON object. | The request body is empty, or parsed to something other than a JSON object (for example an array or a string). |
| 404 | Chat not found or you do not have permission to access it. | No chat with that id belongs to the organization. |
| 410 | This endpoint has been retired (v1/chat/update). | Always, for API callers. This check runs before authentication and consumes no quota. |
| 422 | The 'chatId' field must be provided as a non-empty string. | `chatId` is missing, empty, or not a string. |
| 422 | A valid chatId is required. | `chatId` is only whitespace. |
| 422 | The 'messages' field must be provided as an array. | `messages` is missing or not an array. |
| 422 | Message at index <n> must be an object. | An entry of `messages` is not an object. |
| 422 | Message at index <n> must have a 'role' field. | A message has no string `role`. |
| 422 | Message at index <n> has invalid role '<role>'. Must be one of: user, assistant, system. | `role` is anything other than `user`, `assistant` or `system`. |
| 422 | Message at index <n> must have a 'content' field. | `content` is missing or null. |
| 422 | Message at index <n> has empty content array. Must have at least one content part. | `content` is an empty array. |
| 422 | Message at index <n> has invalid content. Must be either a string or an array of content parts. | `content` is neither a string nor an array. |
| 422 | Message at index <n>: Content part at index <i> must be an object. | A content part is not an object. |
| 422 | Message at index <n>: Content part at index <i> must have a 'type' field. | A content part has no string `type`. |
| 422 | Message at index <n>: Content part at index <i> has invalid type '<type>'. Must be one of: input_text, output_text, input_image, output_slots, output_status. | `type` is not one of the five content part types. |
| 422 | Message at index <n>: Content part at index <i> with type '<type>' must have a 'text' property. | An `input_text` or `output_text` part has no string `text`. |
| 422 | Message at index <n>: Content part at index <i> with type '<type>' should not have '<field>' property. | A part carries a field that belongs to another type (for example `image_url` on an `input_text` part, or `text` on an `output_slots` part). |
| 422 | Message at index <n>: Content part at index <i> with type 'input_image' must have an 'image_url' string property. | An `input_image` part has no string `image_url`. |
| 422 | Message at index <n>: Content part at index <i> with type 'output_slots' must have a 'slots' array property. | An `output_slots` part has no `slots` array. |
| 422 | Message at index <n>: Content part at index <i>: slot at index <j> must be an object. | An entry of `slots` is not an object. |
| 422 | Message at index <n>: Content part at index <i>: slot at index <j> must have an 'id' string property. | A slot has no string `id`. |
| 422 | Message at index <n>: Content part at index <i> with type 'output_status' must have a 'status' string property. | An `output_status` part has no string `status`. |
| 422 | Message at index <n>: Content part at index <i> with type 'output_status' has invalid status '<status>'. Must be one of: resolved, needs_clarification. | `status` is any other value, including transient markers such as `streaming`. |
| 422 | Validation failed. | The messages passed the checks above but the stored slot rules rejected them on save (for example a `search` slot whose `query` is shorter than 6 characters). `details` lists each offending `path` with its `message`.Body: `{"error":"Validation failed.","details":[{"path":"messages.1.content.1.slots.0.query","message":"Path `query` (`tee`) is shorter than the minimum allowed length (6)."}]}` |

### Shared authentication, quota and rate-limit errors

| Status | Message | When |
| --- | --- | --- |
| 401 | API key missing. | The `Authorization` header is absent, is not `Bearer <key>`, or the key does not have three dash-separated segments. |
| 401 | Authentication failed: public key is invalid or not recognized. | A public-key endpoint was called with a key that does not exist. |
| 401 | Authentication failed: private key provided instead of a public key. | A public-key endpoint was called with an `sgpt-sk-…` key. |
| 401 | Authentication failed: token is not recognized. | A private-key endpoint was called with a key whose lookup segment does not exist. |
| 401 | Authentication failed: private key is invalid. | A private-key endpoint was called with a key whose secret does not match. |
| 401 | Authentication failed: public key provided instead of a private key. | A private-key endpoint was called with an `sgpt-pk-…` key. |
| 401 | Authentication failed: bearer token format is invalid. | A private key was sent without its `::` lookup segment. |
| 401 | Authentication failed: API key could not be read. Regenerate the key. | The key's embedded organization data could not be decrypted or parsed. |
| 403 | Demo mode is not available for private-key routes. Demos are only supported with public API keys. | The demo key was sent to a private-key endpoint. |
| 403 | Demo mode is not supported on this API route. Check the documentation for available demo endpoints. | The demo key was sent to a public-key endpoint that opts out of demo mode. |
| 403 | No active subscription for this organization. | The organization that owns the key has no active subscription. |
| 403 | No quota found for organization "<organizationId>". | The organization has no quota record for the current billing period. |
| 403 | No entitlement for "<resource>". | The plan's quota template has no entry for this endpoint. |
| 403 | Access denied to "<resource>". | The plan's quota template turns this endpoint off. |
| 429 | Monthly quota exceeded for "<resource>" (<quota>/<quota> used). | The billing-period quota for this endpoint is exhausted. `Retry-After` gives the seconds until the period resets. |
| 429 | RPM limit exceeded for "<resource>" (<used>/<limit> used). | More than the allowed requests per minute were sent. `Retry-After` is 60. |
| 500 | Internal server error. | An unexpected failure on the server. The message is always this string; details are logged, never returned. Quota consumed by the request is refunded, as it is for every 5xx response. |
