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

# Send message to AI assistant

> Send a message to the AI trading assistant and receive a streaming response
via Server-Sent Events (SSE).

**Authentication:** Requires a JWT from `/v1/auth/verify` as a Bearer token.

**Rate limiting:** 20 requests per minute per wallet (configurable via `AI_RATE_LIMIT_RPM`).

**Response format:** The response is an SSE stream (`text/event-stream`).
Each event has an `event` type and JSON `data` field. The stream ends with
a `done` event containing the conversation ID and token usage.

**Conversation continuity:** Omit `conversation_id` to start a new conversation.
Include it to continue an existing conversation with message history.

**Trade boundary:** A `strategy` event is a proposal, not an order.
The model has no order-placement tool. In the Joyride app, the user taps
Buy or Sell and the client keeps that intent while it completes wallet
authentication, any required USDC deposit, and final order submission.
Account data failures are not represented as a zero or fallback balance.

**SSE event types:**
- `text` — AI-generated text chunk (streamed incrementally)
- `tool_start` — Tool execution started (for UX loading indicators)
- `tool_result` — Tool execution completed with summary
- `strategy` — Trade recommendation card with a client-owned Buy or Sell action
- `table` — Tabular data display
- `options_chain` — Options chain data
- `price_quote` — Single instrument price quote
- `account_summary` — Account balance overview
- `order_status` — Order placement/cancellation result
- `error` — Error during processing (non-fatal, stream may continue)
- `done` — Stream complete with conversation ID and usage stats

**Data conventions in SSE events:**
Unlike the main REST API which uses internal units (micros, millicontracts),
AI Chat SSE events use human-readable units:
- Prices in USD (e.g., `1.50` not `1500000`)
- Sizes in contracts (e.g., `2.0` not `2000`)
- Balances in USD (e.g., `10000.0` not `10000000000`)




## OpenAPI

````yaml /_generated/openapi.yaml post /v1/ai/chat
openapi: 3.1.0
info:
  title: Joyride Exchange REST API
  version: 1.0.0
  description: >
    REST API for the Joyride 0DTE Options Exchange.


    ## Authentication


    **Public endpoints** (`/health`, `/v1/market/*`, `/v1/spot/*`,
    `/v1/oracle/*`) require no authentication.


    **Competition prize claims** (`/v1/competition/claim`) are
    self-authenticated

    by a Solana ed25519 signature over the wallet, Discord handle, and payout

    destination in the request body. No JWT is required for that endpoint.


    **Account endpoints** (`/v1/account/*`, `/v1/orders/*`,
    `/v1/social/profile`, `/v1/social/avatar`) require JWT authentication via
    one of:

    1. `Authorization: Bearer <jwt>` header (primary — native clients)

    2. `Cookie: joyride_session=<jwt>` (web clients, set automatically by
    `/v1/auth/verify`)


    **Withdrawal endpoints** (`/withdrawals`, `/v1/withdrawals`) require the

    `Authorization: Bearer <jwt>` header. A session cookie alone is not
    accepted.


    Obtain a JWT by completing the SIWS (Sign In With Solana) flow:

    1. `POST /v1/auth/nonce` with your wallet address to get a nonce

    2. Sign the canonical SIWS message with your wallet

    3. `POST /v1/auth/verify` with wallet, signature, and message to receive a
    JWT


    **Mutating admin endpoints** require a bearer token:

    ```

    Authorization: Bearer <ADMIN_TOKEN>

    ```


    ## Data Conventions


    - **Prices**: Integer values in USDC micros (1 USDC = 1,000,000 micros).
      Example: `1500000` = $1.50
    - **Sizes**: Integer values in millicontracts (1 contract = 1000
    millicontracts).
      Example: `1000` = 1 contract
    - **Balances**: USDC micros. Example: `10_000_000_000` = $10,000

    - **Timestamps**: Unix microseconds (µs since epoch)

    - **Instrument IDs**: Format `{ASSET}_USDC-{DMMMYY}-{STRIKE}-{C|P}`.
      Example: `SOL_USDC-28FEB26-150-C`

    ## Trading


    **Trading is WebSocket-only.** The HTTP API has no order placement
    endpoints.

    See the AsyncAPI spec for WebSocket trading methods.
  contact:
    name: Joyride Engineering
    email: engineering@joyride.exchange
  license:
    name: Proprietary
servers:
  - url: https://joyride.exchange/api
    description: Production
security: []
tags:
  - name: Authentication
    description: |
      SIWS (Sign In With Solana) authentication flow. Obtain a JWT for use
      with all authenticated endpoints. No prior authentication required.
  - name: Health
    description: Service health check.
  - name: Market Data
    description: Publicly accessible market data. No authentication required.
  - name: Account
    description: User-specific account data. Requires user identification.
  - name: Orders
    description: User order history. Requires user identification.
  - name: Withdrawals
    description: Request signed withdrawal authorizations and list withdrawal history.
  - name: Social
    description: Social features — profiles, leaderboard, and activity.
  - name: Referrals
    description: Referral-code validation and attribution surfaces.
  - name: Competition
    description: Competition-specific collection flows.
  - name: Spot
    description: Spot prices and volatility data.
  - name: Oracle
    description: Oracle data — prices, TWAP previews, and settlement timing.
  - name: AI Chat
    description: >
      AI-powered trading assistant. Uses SIWS (Sign In With Solana)
      authentication

      and JWT sessions. Returns responses as Server-Sent Events (SSE).
  - name: Admin
    description: Administrative operations. Requires admin bearer token.
paths:
  /v1/ai/chat:
    post:
      tags:
        - AI Chat
      summary: Send message to AI assistant
      description: >
        Send a message to the AI trading assistant and receive a streaming
        response

        via Server-Sent Events (SSE).


        **Authentication:** Requires a JWT from `/v1/auth/verify` as a Bearer
        token.


        **Rate limiting:** 20 requests per minute per wallet (configurable via
        `AI_RATE_LIMIT_RPM`).


        **Response format:** The response is an SSE stream
        (`text/event-stream`).

        Each event has an `event` type and JSON `data` field. The stream ends
        with

        a `done` event containing the conversation ID and token usage.


        **Conversation continuity:** Omit `conversation_id` to start a new
        conversation.

        Include it to continue an existing conversation with message history.


        **Trade boundary:** A `strategy` event is a proposal, not an order.

        The model has no order-placement tool. In the Joyride app, the user taps

        Buy or Sell and the client keeps that intent while it completes wallet

        authentication, any required USDC deposit, and final order submission.

        Account data failures are not represented as a zero or fallback balance.


        **SSE event types:**

        - `text` — AI-generated text chunk (streamed incrementally)

        - `tool_start` — Tool execution started (for UX loading indicators)

        - `tool_result` — Tool execution completed with summary

        - `strategy` — Trade recommendation card with a client-owned Buy or Sell
        action

        - `table` — Tabular data display

        - `options_chain` — Options chain data

        - `price_quote` — Single instrument price quote

        - `account_summary` — Account balance overview

        - `order_status` — Order placement/cancellation result

        - `error` — Error during processing (non-fatal, stream may continue)

        - `done` — Stream complete with conversation ID and usage stats


        **Data conventions in SSE events:**

        Unlike the main REST API which uses internal units (micros,
        millicontracts),

        AI Chat SSE events use human-readable units:

        - Prices in USD (e.g., `1.50` not `1500000`)

        - Sizes in contracts (e.g., `2.0` not `2000`)

        - Balances in USD (e.g., `10000.0` not `10000000000`)
      operationId: postAiChat
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AiChatRequest'
      responses:
        '200':
          description: SSE stream of AI response events
          content:
            text/event-stream:
              schema:
                type: string
                description: |
                  Server-Sent Events stream. Each event has format:
                  ```
                  event: <type>
                  data: <json>
                  ```
              examples:
                text_response:
                  summary: Text-only response
                  value: >
                    event: text

                    data: {"content":"SOL is currently trading at $200."}


                    event: done

                    data:
                    {"conversation_id":"550e8400-e29b-41d4-a716-446655440000","usage":{"input_tokens":150,"output_tokens":45}}
                tool_use_response:
                  summary: Response with tool use
                  value: >
                    event: tool_start

                    data: {"tool":"get_account","id":"call_1"}


                    event: tool_result

                    data:
                    {"tool":"get_account","id":"call_1","summary":"Balance:
                    $10,000.00"}


                    event: account_summary

                    data:
                    {"available":10000.0,"locked":500.0,"total":10500.0,"position_count":2}


                    event: text

                    data: {"content":"Your account has $10,000 available."}


                    event: done

                    data:
                    {"conversation_id":"550e8400-e29b-41d4-a716-446655440000","usage":{"input_tokens":250,"output_tokens":80}}
        '400':
          description: >-
            Invalid request (empty message, message too long, invalid
            conversation_id)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiErrorResponse'
        '401':
          description: Missing or invalid JWT
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiErrorResponse'
        '404':
          description: Conversation not found or not owned by wallet
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiErrorResponse'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiErrorResponse'
      security:
        - aiAuth: []
components:
  schemas:
    AiChatRequest:
      type: object
      properties:
        message:
          type: string
          description: User message text (max 10,000 characters)
          example: What's the current price of SOL?
          maxLength: 10000
        conversation_id:
          type: string
          format: uuid
          description: >-
            Existing conversation ID to continue. Omit to start a new
            conversation.
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - message
    AiErrorResponse:
      type: object
      description: Error response from AI endpoints
      properties:
        error:
          type: string
          description: Human-readable error message
          example: Invalid or missing JWT
        code:
          type: string
          description: Machine-readable error code
          enum:
            - UNAUTHORIZED
            - RATE_LIMITED
            - INVALID_REQUEST
            - NOT_FOUND
            - INTERNAL_ERROR
            - LLM_UNAVAILABLE
            - LLM_ERROR
            - TOOL_ERROR
            - CONVERSATION_NOT_FOUND
            - ALREADY_DELETED
            - INVALID_TITLE
            - INVALID_CURSOR
            - INVALID_LIMIT
            - INVALID_ID
          example: UNAUTHORIZED
      required:
        - error
        - code
  securitySchemes:
    aiAuth:
      type: http
      scheme: bearer
      description: |
        JWT obtained from POST /v1/auth/verify after SIWS authentication.
        Include as: `Authorization: Bearer <jwt>`

````