openapi: 3.1.1
info:
  title: Assistant Core Developer API
  version: 1.0.0-preview
  description: |
    Canonical Preview contract for the versioned Assistant Core Developer API.
    Preview operations may change before general availability; see the public
    documentation and changelog before upgrading an integration.
  contact:
    name: Assistant Core Support
    url: https://support.assistantcore.com
  license:
    name: Proprietary
servers:
  - url: https://api.assistantcore.com
    description: Production
security:
  - DeveloperCredential: []
paths:
  /v1/chat/responses:
    post:
      tags: [Chat]
      operationId: createResponse
      x-required-scope: chat:write
      summary: Create a chat response
      description: "Use `stream: true` to receive Server-Sent Events. `Idempotency-Key` applies to response creation, not token replay."
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CreateResponseRequest" }
      responses:
        "200":
          description: >-
            Completed response or SSE stream, selected by `stream`. Retrying a completed
            idempotent request returns its stored metadata with `Idempotent-Replayed: true`.
          headers:
            {
              X-Request-ID: { $ref: "#/components/headers/RequestId" },
              Idempotent-Replayed:
                { $ref: "#/components/headers/IdempotentReplayed" },
              RateLimit-Limit: { $ref: "#/components/headers/RateLimitLimit" },
              RateLimit-Remaining:
                { $ref: "#/components/headers/RateLimitRemaining" },
              RateLimit-Reset: { $ref: "#/components/headers/RateLimitReset" },
            }
          content:
            application/json:
              { schema: { $ref: "#/components/schemas/Response" } }
            text/event-stream:
              schema: { type: string }
              examples:
                {
                  delta:
                    {
                      value: "event: response.output_text.delta\ndata: {\"type\":\"response.output_text.delta\",\"sequence\":3,\"response_id\":\"resp_…\",\"delta\":\"Hello\"}\n\n",
                    },
                }
        "4XX": { $ref: "#/components/responses/Error" }
        default: { $ref: "#/components/responses/Error" }
  /v1/responses/{response_id}:
    get:
      tags: [Chat]
      operationId: getResponse
      x-required-scope: chat:write
      summary: Retrieve a finished response
      description: Available once the response finishes; in-flight responses return `RESPONSE_NOT_FOUND`.
      parameters:
        [
          {
            name: response_id,
            in: path,
            required: true,
            schema: { type: string, pattern: "^resp_" },
          },
          { $ref: "#/components/parameters/ExternalUserId" },
        ]
      responses:
        {
          "200":
            {
              description: Response,
              content:
                {
                  application/json:
                    { schema: { $ref: "#/components/schemas/Response" } },
                },
            },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
  /v1/files:
    post:
      tags: [Files]
      operationId: createFile
      x-required-scope: files:write
      summary: Upload a file for the external actor
      requestBody:
        required: true
        content:
          {
            multipart/form-data:
              {
                schema:
                  {
                    type: object,
                    required: [file, external_user_id],
                    properties:
                      {
                        file: { type: string, format: binary },
                        external_user_id:
                          { $ref: "#/components/schemas/ExternalUserId" },
                      },
                  },
              },
          }
      responses:
        {
          "201":
            {
              description: Uploaded file,
              content:
                {
                  application/json:
                    { schema: { $ref: "#/components/schemas/File" } },
                },
            },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
  /v1/conversations/{conversation_id}:
    get:
      tags: [Conversations]
      operationId: getConversation
      x-required-scope: conversations:read
      summary: Retrieve a conversation
      parameters:
        [
          { $ref: "#/components/parameters/ConversationId" },
          { $ref: "#/components/parameters/ExternalUserId" },
        ]
      responses:
        {
          "200":
            {
              description: Conversation,
              content:
                {
                  application/json:
                    { schema: { $ref: "#/components/schemas/Conversation" } },
                },
            },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
  /v1/conversations/{conversation_id}/messages:
    get:
      tags: [Conversations]
      operationId: listConversationMessages
      x-required-scope: conversations:read
      summary: List messages in a conversation
      parameters:
        [
          { $ref: "#/components/parameters/ConversationId" },
          { $ref: "#/components/parameters/ExternalUserId" },
          {
            name: limit,
            in: query,
            schema: { type: integer, minimum: 1, maximum: 100, default: 50 },
          },
          {
            name: after,
            in: query,
            description: "`last_id` of the previous page.",
            schema: { type: string, format: uuid },
          },
        ]
      responses:
        {
          "200":
            {
              description: Messages,
              content:
                {
                  application/json:
                    { schema: { $ref: "#/components/schemas/MessagePage" } },
                },
            },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
  /v1/messages/{message_id}/feedback:
    post:
      tags: [Feedback]
      operationId: createMessageFeedback
      x-required-scope: feedback:write
      summary: Record feedback for a message
      parameters:
        [
          {
            name: message_id,
            in: path,
            required: true,
            schema: { type: string, format: uuid },
          },
        ]
      requestBody:
        {
          required: true,
          content:
            {
              application/json:
                {
                  schema:
                    {
                      type: object,
                      required: [external_user_id, rating],
                      properties:
                        {
                          external_user_id:
                            { $ref: "#/components/schemas/ExternalUserId" },
                          rating: { type: string, enum: [up, down] },
                        },
                    },
                },
            },
        }
      responses:
        {
          "204": { description: Feedback recorded },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
  /v1/users/{external_user_id}:
    delete:
      tags: [Users]
      operationId: deleteUser
      x-required-scope: users:delete
      summary: Erase an external user's data
      description: >-
        Permanently deletes the external user's conversations, messages, memories, files,
        and usage rows. Idempotent: unknown users also return `204`.
      parameters:
        [
          {
            name: external_user_id,
            in: path,
            required: true,
            schema: { $ref: "#/components/schemas/ExternalUserId" },
          },
        ]
      responses:
        {
          "204": { description: User data erased },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
  /v1/voice/sessions:
    post:
      tags: [Voice]
      operationId: createVoiceSession
      x-required-scope: voice:connect
      summary: Create a short-lived, single-use browser session
      requestBody:
        {
          required: true,
          content:
            {
              application/json:
                {
                  schema:
                    { $ref: "#/components/schemas/CreateVoiceSessionRequest" },
                },
            },
        }
      responses:
        {
          "201":
            {
              description: Session token,
              content:
                {
                  application/json:
                    { schema: { $ref: "#/components/schemas/VoiceSession" } },
                },
            },
          "4XX": { $ref: "#/components/responses/Error" },
          default: { $ref: "#/components/responses/Error" },
        }
components:
  securitySchemes:
    DeveloperCredential:
      {
        type: http,
        scheme: bearer,
        bearerFormat: ac_<public-id>_<secret><checksum>,
      }
  parameters:
    IdempotencyKey:
      {
        name: Idempotency-Key,
        in: header,
        required: false,
        schema: { type: string, minLength: 1, maxLength: 255 },
      }
    ConversationId:
      {
        name: conversation_id,
        in: path,
        required: true,
        schema: { type: string, format: uuid },
      }
    ExternalUserId:
      {
        name: external_user_id,
        in: query,
        required: true,
        schema: { $ref: "#/components/schemas/ExternalUserId" },
      }
  headers:
    RequestId: { schema: { type: string } }
    IdempotentReplayed:
      {
        description: Present with `true` when a completed idempotent request is replayed.,
        schema: { type: string, enum: ["true"] },
      }
    RateLimitLimit: { schema: { type: integer } }
    RateLimitRemaining: { schema: { type: integer } }
    RateLimitReset:
      {
        schema:
          {
            type: integer,
            description: Seconds until the current window resets (delta-seconds),
          },
      }
  responses:
    Error:
      {
        description: Stable API error,
        content:
          {
            application/json:
              { schema: { $ref: "#/components/schemas/Error" } },
          },
      }
  schemas:
    ExternalUserId:
      {
        type: string,
        minLength: 1,
        maxLength: 256,
        description: Opaque customer identifier; scoped to the credential's assistant.,
      }
    CreateResponseRequest:
      type: object
      required: [external_user_id, input]
      properties:
        external_user_id: { $ref: "#/components/schemas/ExternalUserId" }
        conversation_id: { type: string, format: uuid }
        input: { type: string, minLength: 1, maxLength: 100000 }
        file_ids:
          { type: array, maxItems: 10, items: { type: string, format: uuid } }
        model: { type: string, description: Optional permitted model override. }
        stream: { type: boolean, default: false }
      additionalProperties: false
    Response:
      {
        type: object,
        required: [id, object, status, conversation_id, output_text],
        properties:
          {
            id: { type: string, pattern: "^resp_" },
            object: { const: response },
            status: { type: string, enum: [completed, failed, incomplete] },
            conversation_id: { type: [string, "null"], format: uuid },
            output_text: { type: string },
            message_id: { type: string, format: uuid },
            request_id: { type: string },
          },
      }
    File:
      {
        type: object,
        required: [id, object, filename, bytes],
        properties:
          {
            id: { type: string, format: uuid },
            object: { const: file },
            filename: { type: string },
            bytes: { type: integer },
            mime_type: { type: string },
          },
      }
    Conversation:
      {
        type: object,
        required: [id, object, created_at],
        properties:
          {
            id: { type: string, format: uuid },
            object: { const: conversation },
            created_at: { type: string, format: date-time },
          },
      }
    Message:
      {
        type: object,
        required: [id, object, role, content, created_at],
        properties:
          {
            id: { type: string, format: uuid },
            object: { const: message },
            role: { type: string, enum: [user, assistant] },
            content: { type: string },
            created_at: { type: string, format: date-time },
          },
      }
    MessagePage:
      {
        type: object,
        required: [object, data, has_more, first_id, last_id],
        properties:
          {
            object: { const: list },
            data:
              { type: array, items: { $ref: "#/components/schemas/Message" } },
            has_more: { type: boolean },
            first_id: { type: [string, "null"], format: uuid },
            last_id:
              {
                type: [string, "null"],
                format: uuid,
                description: Pass as `after` to fetch the next page.,
              },
          },
      }
    CreateVoiceSessionRequest:
      {
        type: object,
        required:
          [external_user_id, mode, input_audio_format, output_audio_format],
        properties:
          {
            external_user_id: { $ref: "#/components/schemas/ExternalUserId" },
            conversation_id: { type: string, format: uuid },
            mode: { type: string, enum: [standard, realtime] },
            turn_detection:
              {
                type: string,
                enum: [manual, auto, server_vad],
                default: manual,
                description: server_vad is valid only in realtime mode.,
              },
            max_session_seconds:
              {
                type: integer,
                minimum: 10,
                maximum: 1800,
                description: Optional trusted per-session duration capped by the global maximum.,
              },
            input_audio_format: { $ref: "#/components/schemas/AudioFormat" },
            output_audio_format: { $ref: "#/components/schemas/AudioFormat" },
          },
        additionalProperties: false,
      }
    AudioFormat:
      {
        type: object,
        required: [codec, sample_rate_hz, channels],
        properties:
          {
            codec: { type: string, enum: [pcm_s16le, opus] },
            sample_rate_hz: { type: integer, enum: [16000, 24000] },
            channels: { type: integer, const: 1 },
          },
      }
    VoiceSession:
      {
        type: object,
        required: [id, token, expires_at, websocket_url],
        properties:
          {
            id: { type: string, pattern: "^sess_" },
            token:
              {
                type: string,
                writeOnly: true,
                description: Returned once; send in the first WebSocket event.,
              },
            expires_at: { type: string, format: date-time },
            websocket_url: { type: string, format: uri },
          },
      }
    Error:
      {
        type: object,
        required: [code, message, request_id, retryable],
        properties:
          {
            code:
              {
                type: string,
                enum:
                  [
                    INVALID_API_KEY,
                    API_KEY_EXPIRED,
                    API_KEY_REVOKED,
                    INSUFFICIENT_SCOPE,
                    IP_NOT_ALLOWED,
                    ASSISTANT_INACTIVE,
                    FEATURE_NOT_AVAILABLE,
                    FILE_UPLOAD_DISABLED,
                    VOICE_DISABLED,
                    ACTOR_CONFLICT,
                    INSUFFICIENT_CREDITS,
                    RATE_LIMITED,
                    IDEMPOTENCY_CONFLICT,
                    REQUEST_IN_PROGRESS,
                    CONVERSATION_NOT_FOUND,
                    MESSAGE_NOT_FOUND,
                    FILE_NOT_FOUND,
                    RESPONSE_NOT_FOUND,
                    INVALID_CURSOR,
                    VALIDATION_ERROR,
                    UNSUPPORTED_FILE_TYPE,
                    FILE_TOO_LARGE,
                    INVALID_AUDIO_FORMAT,
                    CONTEXT_TOO_LARGE,
                    UPSTREAM_UNAVAILABLE,
                    RATE_LIMIT_UNAVAILABLE,
                    INTERNAL_SERVER_ERROR,
                  ],
              },
            message: { type: string },
            details: { type: [object, "null"], additionalProperties: true },
            request_id: { type: string },
            retryable: { type: boolean },
          },
      }
