openapi: 3.1.0
x-atlas-contract-status: implementation-pending
info:
  title: Atlas Messages API
  version: 1.0.0
  summary: Stateless, owner-scoped Atlas chat API.
  description: >-
    Normative target contract for the Atlas Messages API. This contract is
    implementation-pending: it describes the future Sessions-equivalent
    runtime, not the currently deployed narrow evaluation endpoint.
jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
servers:
  - url: https://api.trentsoftware.in
    description: Atlas public API edge
security:
  - BasicAuth: []
    AtlasApiKey: []
tags:
  - name: Messages
    description: Stateless Atlas chat and token estimation.
paths:
  /v1/messages:
    post:
      tags: [Messages]
      operationId: createMessage
      summary: Create an Atlas message response.
      description: >-
        The caller supplies the complete bounded system, user, and assistant
        history on every request. There is no session or conversation id. Atlas
        selects all runtime tools server-side; callers cannot define tools or
        tool_choice. A repeated owner, Idempotency-Key, and request digest
        replays the original terminal response. Reusing an owner/key pair with
        a different request digest returns 409.
      security:
        - BasicAuth: []
          AtlasApiKey: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MessageRequest'
            examples:
              nonStreamingText:
                summary: Non-streaming text request
                value:
                  model: atlas-data360-v1
                  max_tokens: 1024
                  stream: false
                  system: You are a concise, grounded assistant.
                  messages:
                    - role: user
                      content: Summarize my connected data sources.
              streamingRequest:
                summary: Streaming request
                value:
                  model: atlas-data360-v1
                  max_tokens: 1024
                  stream: true
                  messages:
                    - role: user
                      content: What can you help me with?
      responses:
        '200':
          description: >-
            A JSON message when stream is false, or an Anthropic-style
            server-sent event sequence when stream is true.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
              examples:
                text:
                  value:
                    id: msg_018f6a6b-5678-7def-8123-456789abcdef
                    type: message
                    role: assistant
                    model: atlas-data360-v1
                    content:
                      - type: text
                        text: I found two connected data sources.
                    stop_reason: end_turn
                    stop_sequence: null
                    usage:
                      input_tokens: 18
                      output_tokens: 9
            text/event-stream:
              schema:
                $ref: '#/components/schemas/ServerSentEventStream'
              examples:
                events:
                  value: |
                    event: message_start
                    data: {"type":"message_start","message":{"id":"msg_018f6a6b-5678-7def-8123-456789abcdef","type":"message","role":"assistant","model":"atlas-data360-v1","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":18,"output_tokens":0}}}

                    event: content_block_delta
                    data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"I found two connected data sources."}}

                    event: message_stop
                    data: {"type":"message_stop"}
        '400':
          $ref: '#/components/responses/InvalidRequest'
        '401':
          $ref: '#/components/responses/AuthenticationError'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'
        '413':
          $ref: '#/components/responses/RequestTooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedMediaType'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ApiError'
  /v1/messages/count_tokens:
    post:
      tags: [Messages]
      operationId: countMessageTokens
      summary: Estimate tokens for a Messages request without execution.
      description: >-
        Validates the supplied complete history and estimates its input tokens.
        This operation does not create a conversation, start a model run,
        execute a tool, or reserve an idempotency key.
      security:
        - BasicAuth: []
          AtlasApiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CountTokensRequest'
            examples:
              request:
                value:
                  model: atlas-data360-v1
                  max_tokens: 1024
                  stream: false
                  messages:
                    - role: user
                      content: Count these tokens without running Atlas.
      responses:
        '200':
          description: Validated input-token estimate.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CountTokensResponse'
              examples:
                estimate:
                  value:
                    input_tokens: 11
        '400':
          $ref: '#/components/responses/InvalidRequest'
        '401':
          $ref: '#/components/responses/AuthenticationError'
        '413':
          $ref: '#/components/responses/RequestTooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedMediaType'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ApiError'
components:
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
      description: Required HTTP Basic authentication at the public API edge.
    AtlasApiKey:
      type: apiKey
      in: header
      name: X-Atlas-API-Key
      description: >-
        Required Atlas API credential. Send this header only to the configured
        API edge. The edge translates it to an internal bearer credential and
        does not forward the original header.
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: >-
        A caller-generated, opaque key. Its replay scope is the authenticated
        Atlas owner, the key, and the canonical request digest.
      schema:
        type: string
        minLength: 1
        maxLength: 256
        pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$'
  responses:
    InvalidRequest:
      description: Request JSON, shape, bounds, or request semantics are invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalidRequest:
              value:
                type: error
                error:
                  type: invalid_request_error
                  message: Request does not match the Atlas Messages contract.
    AuthenticationError:
      description: Basic Auth or X-Atlas-API-Key authentication failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            authentication:
              value:
                type: error
                error:
                  type: authentication_error
                  message: Authentication failed.
    IdempotencyConflict:
      description: >-
        The supplied Idempotency-Key is already associated with a different
        canonical request digest for this owner.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            conflict:
              value:
                type: error
                error:
                  type: idempotency_conflict
                  message: Idempotency-Key was previously used for a different request.
    RequestTooLarge:
      description: The request exceeds the 256 KiB body limit.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            tooLarge:
              value:
                type: error
                error:
                  type: request_too_large
                  message: Request body exceeds the 256 KiB limit.
    UnsupportedMediaType:
      description: Content-Type must be application/json.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            mediaType:
              value:
                type: error
                error:
                  type: unsupported_media_type
                  message: Content-Type must be application/json.
    RateLimited:
      description: The authenticated owner exceeded an API limit.
      headers:
        Retry-After:
          required: false
          schema:
            type: integer
            minimum: 1
          description: Seconds until the caller may retry.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            rateLimited:
              value:
                type: error
                error:
                  type: rate_limit_error
                  message: Retry later.
    ApiError:
      description: The API could not complete the request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            apiError:
              value:
                type: error
                error:
                  type: api_error
                  message: Atlas could not complete the request.
  schemas:
    MessageRequest:
      type: object
      additionalProperties: false
      required: [model, max_tokens, stream, messages]
      properties:
        model:
          $ref: '#/components/schemas/Model'
        max_tokens:
          type: integer
          minimum: 1
          maximum: 4096
        stream:
          type: boolean
          description: false returns JSON; true returns text/event-stream.
        system:
          $ref: '#/components/schemas/SystemContent'
        messages:
          type: array
          minItems: 1
          maxItems: 64
          items:
            $ref: '#/components/schemas/ClientMessage'
      x-atlas-max-request-bytes: 262144
      x-atlas-stateless-history: true
      x-atlas-runtime-tools: server-selected
    CountTokensRequest:
      allOf:
        - $ref: '#/components/schemas/MessageRequest'
        - type: object
          properties:
            stream:
              const: false
    Model:
      type: string
      const: atlas-data360-v1
    SystemContent:
      oneOf:
        - $ref: '#/components/schemas/BoundedText'
        - type: array
          minItems: 1
          maxItems: 64
          items:
            $ref: '#/components/schemas/TextBlock'
    ClientMessage:
      oneOf:
        - $ref: '#/components/schemas/SystemMessage'
        - $ref: '#/components/schemas/UserMessage'
        - $ref: '#/components/schemas/AssistantMessage'
    SystemMessage:
      type: object
      additionalProperties: false
      required: [role, content]
      properties:
        role:
          const: system
        content:
          $ref: '#/components/schemas/SystemContent'
    UserMessage:
      type: object
      additionalProperties: false
      required: [role, content]
      properties:
        role:
          const: user
        content:
          $ref: '#/components/schemas/UserContent'
    AssistantMessage:
      type: object
      additionalProperties: false
      required: [role, content]
      properties:
        role:
          const: assistant
        content:
          $ref: '#/components/schemas/AssistantContent'
    UserContent:
      oneOf:
        - $ref: '#/components/schemas/BoundedText'
        - type: array
          minItems: 1
          maxItems: 64
          items:
            oneOf:
              - $ref: '#/components/schemas/TextBlock'
              - $ref: '#/components/schemas/ToolResultBlock'
    AssistantContent:
      oneOf:
        - $ref: '#/components/schemas/BoundedText'
        - type: array
          minItems: 1
          maxItems: 64
          items:
            oneOf:
              - $ref: '#/components/schemas/TextBlock'
              - $ref: '#/components/schemas/ToolUseBlock'
    BoundedText:
      type: string
      minLength: 1
      maxLength: 32768
      x-atlas-max-utf8-bytes: 32768
    TextBlock:
      type: object
      additionalProperties: false
      required: [type, text]
      properties:
        type:
          const: text
        text:
          $ref: '#/components/schemas/BoundedText'
    ToolUseBlock:
      type: object
      additionalProperties: false
      required: [type, id, name, input]
      properties:
        type:
          const: tool_use
        id:
          type: string
          minLength: 1
          maxLength: 256
          pattern: '^toolu_[A-Za-z0-9._:-]+$'
        name:
          type: string
          minLength: 1
          maxLength: 128
          pattern: '^[A-Za-z][A-Za-z0-9_-]*$'
        input:
          $ref: '#/components/schemas/BoundedJsonValue'
      description: >-
        A server-emitted Atlas tool use preserved by the client for history
        replay. It does not let the caller define, select, or authorize a tool.
    ToolResultBlock:
      type: object
      additionalProperties: false
      required: [type, tool_use_id, content]
      properties:
        type:
          const: tool_result
        tool_use_id:
          type: string
          minLength: 1
          maxLength: 256
          pattern: '^toolu_[A-Za-z0-9._:-]+$'
        content:
          $ref: '#/components/schemas/ToolResultContent'
        is_error:
          type: boolean
      description: >-
        Result for a tool use previously emitted by Atlas. Question and
        approval decisions use the bounded structured continuation forms below.
    ToolResultContent:
      oneOf:
        - $ref: '#/components/schemas/BoundedText'
        - type: array
          minItems: 1
          maxItems: 64
          items:
            $ref: '#/components/schemas/TextBlock'
        - $ref: '#/components/schemas/QuestionAnswerContinuation'
        - $ref: '#/components/schemas/ApprovalContinuation'
    QuestionAnswerContinuation:
      type: object
      additionalProperties: false
      required: [type, question_id, answer]
      properties:
        type:
          const: question_answer
        question_id:
          type: string
          minLength: 1
          maxLength: 256
        answer:
          $ref: '#/components/schemas/BoundedText'
    ApprovalContinuation:
      type: object
      additionalProperties: false
      required: [type, approval_id, approved]
      properties:
        type:
          const: approval_response
        approval_id:
          type: string
          minLength: 1
          maxLength: 256
        approved:
          type: boolean
    BoundedJsonValue:
      description: >-
        Bounded JSON emitted by Atlas in a tool_use input. Object members are
        intentionally open only inside this server-emitted replay payload.
      oneOf:
        - type: 'null'
        - type: boolean
        - type: number
        - type: string
          maxLength: 32768
        - type: array
          maxItems: 64
          items:
            $ref: '#/components/schemas/BoundedJsonValue'
        - type: object
          maxProperties: 64
          additionalProperties:
            $ref: '#/components/schemas/BoundedJsonValue'
      x-atlas-max-json-depth: 16
      x-atlas-max-utf8-bytes: 65536
    MessageResponse:
      type: object
      additionalProperties: false
      required: [id, type, role, model, content, stop_reason, stop_sequence, usage]
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 256
          pattern: '^msg_[A-Za-z0-9._:-]+$'
        type:
          const: message
        role:
          const: assistant
        model:
          $ref: '#/components/schemas/Model'
        content:
          type: array
          minItems: 1
          maxItems: 64
          items:
            oneOf:
              - $ref: '#/components/schemas/TextBlock'
              - $ref: '#/components/schemas/ToolUseBlock'
        stop_reason:
          type: [string, 'null']
          enum: [end_turn, tool_use, max_tokens, stop_sequence, null]
        stop_sequence:
          type: [string, 'null']
          maxLength: 256
        usage:
          $ref: '#/components/schemas/Usage'
    Usage:
      type: object
      additionalProperties: false
      required: [input_tokens, output_tokens]
      properties:
        input_tokens:
          type: integer
          minimum: 0
        output_tokens:
          type: integer
          minimum: 0
          maximum: 4096
    CountTokensResponse:
      type: object
      additionalProperties: false
      required: [input_tokens]
      properties:
        input_tokens:
          type: integer
          minimum: 0
    ServerSentEventStream:
      type: string
      contentMediaType: text/event-stream
      description: >-
        UTF-8 server-sent events. Each data field is one JSON value conforming
        to ServerSentEvent; events use the Anthropic message streaming order.
      x-atlas-sse-event-schema:
        $ref: '#/components/schemas/ServerSentEvent'
    ServerSentEvent:
      oneOf:
        - $ref: '#/components/schemas/MessageStartEvent'
        - $ref: '#/components/schemas/ContentBlockStartEvent'
        - $ref: '#/components/schemas/ContentBlockDeltaEvent'
        - $ref: '#/components/schemas/ContentBlockStopEvent'
        - $ref: '#/components/schemas/MessageDeltaEvent'
        - $ref: '#/components/schemas/MessageStopEvent'
        - $ref: '#/components/schemas/PingEvent'
        - $ref: '#/components/schemas/ErrorEvent'
      discriminator:
        propertyName: type
        mapping:
          message_start: '#/components/schemas/MessageStartEvent'
          content_block_start: '#/components/schemas/ContentBlockStartEvent'
          content_block_delta: '#/components/schemas/ContentBlockDeltaEvent'
          content_block_stop: '#/components/schemas/ContentBlockStopEvent'
          message_delta: '#/components/schemas/MessageDeltaEvent'
          message_stop: '#/components/schemas/MessageStopEvent'
          ping: '#/components/schemas/PingEvent'
          error: '#/components/schemas/ErrorEvent'
    MessageStartEvent:
      type: object
      additionalProperties: false
      required: [type, message]
      properties:
        type:
          const: message_start
        message:
          $ref: '#/components/schemas/StreamingMessage'
    StreamingMessage:
      type: object
      additionalProperties: false
      required: [id, type, role, model, content, stop_reason, stop_sequence, usage]
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 256
          pattern: '^msg_[A-Za-z0-9._:-]+$'
        type:
          const: message
        role:
          const: assistant
        model:
          $ref: '#/components/schemas/Model'
        content:
          type: array
          maxItems: 64
          items:
            oneOf:
              - $ref: '#/components/schemas/TextBlock'
              - $ref: '#/components/schemas/ToolUseBlock'
        stop_reason:
          type: 'null'
        stop_sequence:
          type: 'null'
        usage:
          $ref: '#/components/schemas/Usage'
    ContentBlockStartEvent:
      type: object
      additionalProperties: false
      required: [type, index, content_block]
      properties:
        type:
          const: content_block_start
        index:
          type: integer
          minimum: 0
          maximum: 63
        content_block:
          oneOf:
            - $ref: '#/components/schemas/TextBlock'
            - $ref: '#/components/schemas/ToolUseBlock'
    ContentBlockDeltaEvent:
      type: object
      additionalProperties: false
      required: [type, index, delta]
      properties:
        type:
          const: content_block_delta
        index:
          type: integer
          minimum: 0
          maximum: 63
        delta:
          oneOf:
            - $ref: '#/components/schemas/TextDelta'
            - $ref: '#/components/schemas/InputJsonDelta'
    TextDelta:
      type: object
      additionalProperties: false
      required: [type, text]
      properties:
        type:
          const: text_delta
        text:
          $ref: '#/components/schemas/BoundedText'
    InputJsonDelta:
      type: object
      additionalProperties: false
      required: [type, partial_json]
      properties:
        type:
          const: input_json_delta
        partial_json:
          $ref: '#/components/schemas/BoundedText'
    ContentBlockStopEvent:
      type: object
      additionalProperties: false
      required: [type, index]
      properties:
        type:
          const: content_block_stop
        index:
          type: integer
          minimum: 0
          maximum: 63
    MessageDeltaEvent:
      type: object
      additionalProperties: false
      required: [type, delta, usage]
      properties:
        type:
          const: message_delta
        delta:
          type: object
          additionalProperties: false
          required: [stop_reason, stop_sequence]
          properties:
            stop_reason:
              type: string
              enum: [end_turn, tool_use, max_tokens, stop_sequence]
            stop_sequence:
              type: [string, 'null']
              maxLength: 256
        usage:
          type: object
          additionalProperties: false
          required: [output_tokens]
          properties:
            output_tokens:
              type: integer
              minimum: 0
              maximum: 4096
    MessageStopEvent:
      type: object
      additionalProperties: false
      required: [type]
      properties:
        type:
          const: message_stop
    PingEvent:
      type: object
      additionalProperties: false
      required: [type]
      properties:
        type:
          const: ping
    ErrorEvent:
      type: object
      additionalProperties: false
      required: [type, error]
      properties:
        type:
          const: error
        error:
          $ref: '#/components/schemas/ApiErrorObject'
    ErrorResponse:
      type: object
      additionalProperties: false
      required: [type, error]
      properties:
        type:
          const: error
        error:
          $ref: '#/components/schemas/ApiErrorObject'
    ApiErrorObject:
      type: object
      additionalProperties: false
      required: [type, message]
      properties:
        type:
          type: string
          enum:
            - invalid_request_error
            - authentication_error
            - idempotency_conflict
            - request_too_large
            - unsupported_media_type
            - rate_limit_error
            - api_error
        message:
          type: string
          minLength: 1
          maxLength: 1024
