---
title: "Create Turn"
method: POST
path: "/v1/conversations"
tags: ["v1"]
---

# Create Turn

`POST /v1/conversations`

## Request

- Base URL: `https://api.trychannel3.com`
- URL: `https://api.trychannel3.com/v1/conversations`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

Run one conversation turn. Omit `conversation_id` to create the thread with this turn; pass it to continue an existing thread.

## Headers

- `x-user-id` string, nullable: Optional user identifier to attribute clicks and sales to a user in your system. Channel3 appends it to buy URLs in the response.

## Request body

- CreateTurnRequest: Run one turn. Without ``conversation_id`` a new thread is created first.
  - `message` UserMessage, required
    - `role` 'user'
    - `parts` union[]
      - union
        - TextPart
          - `type` 'text'
          - `text` string, required
        - ImagePart: An image by URL. ``data:`` URIs are uploaded and rewritten server-side.
          - `type` 'image'
          - `url` string, required
  - `conversation_id` string, nullable: Existing thread to continue. When omitted, a new thread is created and its id returned.
  - `filters` SearchFilters: Search filters for the search API.
    - `brand_ids` string[], nullable: If provided, only products from these brands will be returned
    - `gender` 'male' | 'female': Product gender. 'unisex' is deprecated: coerced to None on input, never emitted.
    - `conditions` Condition[]: Offer conditions to match (OR). Defaults to ['new'], which also matches offers whose condition is unknown. Pass every value to disable condition filtering.
    - `age` Age[], nullable: Filter by age group. Age-agnostic products are treated as adult products.
    - `price` SearchFilterPrice: Price filter for search. Values are inclusive.
      - `min_price` number, nullable: Minimum price, in dollars and cents
      - `max_price` number, nullable: Maximum price, in dollars and cents
    - `availability` OfferAvailabilityStatus[]: Offer availability statuses to match (OR). Defaults to ['InStock']. An offer with no availability data counts as 'InStock'. Pass every value to disable availability filtering.
    - `sale` 'on_sale'
    - `website_ids` string[], nullable: If provided, only products from these websites will be returned. Accepts website IDs or domains (e.g. "nike.com").
    - `category_ids` string[], nullable: If provided, only products from these categories will be returned. Accepts category slugs. Categories that do not exist, or that are not available for search, are rejected with a 422.
    - `exclude_brand_ids` string[], nullable: If provided, products from these brands will be excluded from the results
    - `exclude_website_ids` string[], nullable: If provided, products from these websites will be excluded from the results. Accepts website IDs or domains (e.g. "nike.com").
    - `exclude_category_ids` string[], nullable: If provided, products in these categories (or their descendants) will be excluded from the results. Accepts category slugs. Categories that do not exist are rejected with a 422.
    - `colors` SearchColorsFilter: [Beta] Color filter wrapper. Holds required colors and optional match mode.
      - `palette` SearchFilterColor[], required: Colors required in matching products. Treated as an AND condition.
        - `hex` string, required: sRGB hex string, e.g. '#a1b2c3'
        - `percentage` number, nullable: Percentage of color, where 1.0 is 100%
      - `match` 'strict' | 'standard' | 'loose': How tightly a product's colors must match the requested palette.
    - `attributes` object, nullable: If provided, only products matching these key/value constraints will be returned. Keys are attribute handles (e.g. 'color', 'material') and values are lists of allowed values (OR within a key, AND across keys). When a category filter is also supplied, all keys must be valid attributes of at least one of the requested categories. See `Category.attributes` for the valid keys and values per category.
    - `dimensions` SearchFilterDimensions: Physical-dimension range filters, matched against the same offer. Matching products have at least one offer satisfying every provided range (alongside any locale/price/availability filters). Values are compared with a small relative tolerance. An offer with no dimension data for a filtered field does not match; note that when a single merchant on a product reports a dimension it is shared across that product's offers, so a matching offer may not itself surface that dimension in the response.
      - `length` SearchFilterLengthDimension
        - `min` number, nullable: Minimum value, in `unit`. Inclusive.
        - `max` number, nullable: Maximum value, in `unit`. Inclusive.
        - `unit` 'mm' | 'cm' | 'm' | 'in' | 'ft', required
      - `width` SearchFilterLengthDimension
        - `min` number, nullable: Minimum value, in `unit`. Inclusive.
        - `max` number, nullable: Maximum value, in `unit`. Inclusive.
        - `unit` 'mm' | 'cm' | 'm' | 'in' | 'ft', required
      - `height` SearchFilterLengthDimension
        - `min` number, nullable: Minimum value, in `unit`. Inclusive.
        - `max` number, nullable: Maximum value, in `unit`. Inclusive.
        - `unit` 'mm' | 'cm' | 'm' | 'in' | 'ft', required
      - `weight` SearchFilterWeightDimension
        - `min` number, nullable: Minimum value, in `unit`. Inclusive.
        - `max` number, nullable: Maximum value, in `unit`. Inclusive.
        - `unit` 'mg' | 'g' | 'kg' | 'oz' | 'lb', required
  - `config` SearchConfig: Search request config: ``BaseConfig`` plus ``mode``.
    - `language` 'en' | 'de' | 'fr' | 'it' | 'es' | 'nl' | 'sv' | 'fi' | 'pt' | 'cs' | 'el' | 'ro' | 'pl': ISO 639-1 language code.
    - `country` 'US' | 'GB' | 'EU' | 'AU' | 'CA' | 'IE' | 'DE' | 'AT' | 'FR' | 'BE' | 'IT' | 'ES' | 'NL' | 'SE' | 'FI' | 'PT' | 'CZ' | 'GR' | 'RO' | 'CH' | 'PL': ISO 3166-1 alpha-2 country code (plus the pan-region ``EU``).
    - `currency` 'USD' | 'CAD' | 'AUD' | 'GBP' | 'EUR' | 'SEK' | 'CZK' | 'RON' | 'CHF' | 'PLN': ISO 4217 currency code.
    - `length_unit` 'mm' | 'cm' | 'm' | 'in' | 'ft'
    - `weight_unit` 'mg' | 'g' | 'kg' | 'oz' | 'lb'
    - `collection_id` string, nullable: Optional saved collection to scope this request. Clauses are ORed. Within a clause, brand/website/category lists are ORed inside each list and ANDed across lists. Request filters further narrow results but cannot widen the collection scope.
    - `offer_refresh_timeout_ms` integer, nullable: Check each returned offer against the merchant's live site, waiting up to this many milliseconds (2000-10000). Offers whose page or variant is gone are dropped and offers found out of stock are returned as out of stock. Adds up to this much latency.
    - `mode` 'keyword' | 'default' | 'agentic': Search strategy. ``default`` (recommended) combines lexical and semantic search and is the right choice for most use cases. ``keyword`` runs lexical search only — use it for real-time, low-latency needs such as ad targeting. ``agentic`` uses an LLM to plan multiple structured sub-searches for complex queries, with higher latency than the other modes.
  - `context` ConversationContext: Partner-supplied context pinned to the top of a conversation thread.
    - `user_context` string, nullable: Who the conversation is with (profile, preferences, session facts).
    - `application_context` string, nullable: What platform or surface is hosting this conversation.
  - `stream` boolean: Stream turn events over SSE (default) or return the assembled turn as JSON.

## Response `200`

`text/event-stream` of `TurnEvent` objects (one `data:` JSON frame each), terminated by `data: [DONE]`. With `stream: false`, a buffered `TurnResult` JSON body instead.

- TurnResult: Buffered equivalent of a streamed turn (``stream: false``).
  - `conversation_id` string, required
  - `turn_id` string, required
  - `usage` TurnUsage, required
    - `credits_charged` integer, required: API credits charged for this turn: 1 for the turn plus each catalog tool billed at its public-API rate.
    - `searches_run` integer, required: Catalog searches executed during this turn.
  - `message` AssistantMessage, required
    - `role` 'assistant'
    - `parts` union[]
      - union
        - TextPart
          - `type` 'text'
          - `text` string, required
        - ToolPart: One catalog tool call and its display payload from an assistant turn.
          - `type` 'tool'
          - `tool_call_id` string, required
          - `tool_name` string, required
          - `input` union
            - SearchProductsInput
              - …
            - ProductIdsInput
              - …
            - UrlLookupInput
              - …
            - ImageSearchInput
              - …
            - SimilarProductsInput
              - …
          - `output` union
            - CatalogDisplayPayload: Client-facing catalog tool result shown on the stream and on ``ToolPart``.
              - …
            - CatalogToolError
              - …
    - `suggestions` string[]: Tap-ready follow-up messages offered after this reply.

## Other responses

- `401`: Unauthorized
- `402`: Payment required
- `404`: Conversation not found
- `409`: Turn already in progress
- `422`: Request validation failed
- `429`: Rate limit exceeded
- `500`: Internal server error
- `503`: All model providers unavailable; retryable

## Changes

- **2026-10-23** `de4ceb9ccdef`: 1 info
  - added the new optional request property `config/offer_refresh_timeout_ms`
- **2026-10-20** `f642382eaf91`: 3 info
  - added the new `PL` enum value to the request property `config/country/anyOf[subschema #1: CountryCode]/`
  - added the new `PLN` enum value to the request property `config/currency/anyOf[subschema #1: CurrencyCode]/`
  - added the new `pl` enum value to the request property `config/language/anyOf[subschema #1: LanguageCode]/`
- **2026-10-19** `7d1e0ccffc95`: 2 info
  - added the new `CH` enum value to the request property `config/country/anyOf[subschema #1: CountryCode]/`
  - added the new `CHF` enum value to the request property `config/currency/anyOf[subschema #1: CurrencyCode]/`
- **2026-10-16** `93329818bdf4`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/channel3-ai/apis/channel3-typescript-api/changes/v1/conversations/post.md)

---

[API](https://skmtc.dev/channel3-ai/apis/channel3-typescript-api.md) - [All operations](https://skmtc.dev/channel3-ai/apis/channel3-typescript-api/llms.txt) - [OpenAPI document](https://skmtc.dev/channel3-ai/apis/channel3-typescript-api/revisions/f9f7b422ab5d?raw)
