# Create a chat

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

- Authentication: private API key, sent as `Authorization: Bearer sgpt-sk-…::…`
- Rate-limit resource: `api.v1.chat.create`
- Demo key: not accepted
- Deprecated: yes
- Web page: https://stylor.ai/guides/rest/v1/create-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.

Create an empty conversation and get its `chatId` back. Use it when you
want a stable id before the first message is sent — for example to
attach analytics or to hand the id to a widget. You do not need this
for normal use: **Send a message** without a `chatId` creates a chat
automatically.

The request has no body. The response includes the full stored record
under `chat`.

## Example request

```bash
curl -X POST "https://stylor.ai/api/v1/chat/create" \
  -H "Authorization: Bearer $STYLOR_API_KEY"
```

## Responses

### 200

The chat was created.

Content type `application/json`:

- `chatId` (string (uuid), required): Id of the new chat. [example `"3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88"`]
- `chat` (ChatRecord, required): The full stored chat record returned by Create a chat. Includes internal fields and derived counters in addition to the `Chat` fields.
  - `_id` (string): Internal storage id. Not used by any endpoint; use `chatId`. [example `"66f1c2d3e4a5b6c7d8e9f0a1"`]
  - `id` (string): Alias of `_id`. [example `"66f1c2d3e4a5b6c7d8e9f0a1"`]
  - `chatId` (string (uuid), required): Unique id of the chat. Use this everywhere else in the API. [example `"3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88"`]
  - `organizationId` (string (uuid), required): The organization that owns the chat (derived from the API key). [example `"7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d"`]
  - `messages` (array<ChatMessage>, required): Always empty for a newly created chat.
    - `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.
  - `createdAt` (string (date-time), required): When the chat was created.
  - `updatedAt` (string (date-time), required): When the chat was last written to.
  - `messageCount` (integer): Number of messages in the thread. [example `0`]
  - `lastMessage` (ChatMessage | null): The most recent message, or `null` when the chat is empty.
    - Option 1: ChatMessage
      - `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.
    - Option 2: null
  - `hasImages` (boolean): Whether any message contains an `input_image` part. [example `false`]

Example:

```json
{
  "chatId": "3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88",
  "chat": {
    "_id": "66f1c2d3e4a5b6c7d8e9f0a1",
    "chatId": "3f0c2a4e-8b1d-4c6a-9e2f-7a5b1c0d9e88",
    "organizationId": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
    "messages": [],
    "createdAt": "2026-09-12T14:03:11.412Z",
    "updatedAt": "2026-09-12T14:03:11.412Z",
    "messageCount": 0,
    "lastMessage": null,
    "hasImages": false,
    "id": "66f1c2d3e4a5b6c7d8e9f0a1"
  }
}
```

## 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 |
| --- | --- | --- |
| 410 | This endpoint has been retired (v1/chat/create). | Always, for API callers. This check runs before authentication and consumes no quota. |

### 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. |
