openapi: 3.0.3
info:
  title: Brek Partner Core Chat API
  version: 1.0.0
  description: |
    Partner-facing API for Brek Core Chat session and event orchestration.
    This contract is optimized for status-driven integrations and agent workflows.
servers:
  - url: https://www.brek.ai
    description: Production
  - url: http://localhost:3000
    description: Local development
tags:
  - name: Sessions
    description: Session lifecycle endpoints
  - name: Events
    description: Event ingestion endpoint
externalDocs:
  description: Human-readable documentation
  url: https://www.brek.ai/docs/partner-core-chat
security:
  - PartnerApiKeyHeader: []
  - PartnerApiKeyBearer: []
  - PartnerApiKeyLegacy: []
paths:
  /api/partner/v1/core-chat/sessions:
    post:
      tags:
        - Sessions
      summary: Create session
      description: Create a partner-scoped chat session for one actor.
      operationId: createPartnerCoreChatSession
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSessionRequest'
            examples:
              minimal:
                value:
                  actor:
                    actorId: partner_user_001
              full:
                value:
                  actor:
                    actorId: partner_user_001
                    timezoneOffsetMinutes: -480
                  channel:
                    workspaceId: partner-workspace
                  conversation:
                    channelId: partner-chat
      responses:
        '200':
          description: Session created
          headers:
            x-request-id:
              $ref: '#/components/headers/XRequestId'
            x-ratelimit-limit:
              $ref: '#/components/headers/XRateLimitLimit'
            x-ratelimit-remaining:
              $ref: '#/components/headers/XRateLimitRemaining'
            x-partner-id:
              $ref: '#/components/headers/XPartnerId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateSessionResponse'
              examples:
                success:
                  value:
                    data:
                      sessionId: sess_1771456953407_g7p6233d
                      tenantId: demo-tenant
                      channel:
                        type: partner_api
                        workspaceId: partner-workspace
                      conversation:
                        id: partner-chat:sess_1771456953407_g7p6233d
                        channelId: partner-chat
                        threadTs: sess_1771456953407_g7p6233d
                      actor:
                        actorId: partner_user_001
                        timezoneOffsetMinutes: -480
                      createdAt: '2026-02-18T23:22:33.407Z'
                      updatedAt: '2026-02-18T23:22:33.407Z'
                      events: []
        '400':
          description: Invalid request payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                actor_required:
                  value:
                    success: false
                    error: actor.actorId is required
                    requestId: 81bfb6d8-c7a5-4fc8-b7f4-48e23931d3a7
                invalid_json:
                  value:
                    success: false
                    error: Invalid JSON payload
                    requestId: e368a7cd-6ba8-4745-9433-a33fe858f4a0
        '401':
          $ref: '#/components/responses/MissingApiKeyError'
        '403':
          $ref: '#/components/responses/InvalidApiKeyError'
        '429':
          $ref: '#/components/responses/RateLimitedError'
        '500':
          description: Unexpected server/proxy error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/GatewayErrorResponse'
                  - $ref: '#/components/schemas/ValidationErrorResponse'

  /api/partner/v1/core-chat/events:
    post:
      tags:
        - Events
      summary: Send event
      description: Send one user turn or one explicit action event into an existing session.
      operationId: sendPartnerCoreChatEvent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendEventRequest'
            examples:
              natural_language:
                value:
                  sessionId: sess_1771456953407_g7p6233d
                  actor:
                    actorId: partner_user_001
                  text: Seattle Mar 20-23 1 room refundable
                  idempotencyKey: demo:sess_1771456953407_g7p6233d:search:001
              action_kind:
                value:
                  sessionId: sess_1771456953407_g7p6233d
                  kind: action_book_option
                  payload:
                    optionId: 1375108c-d021-4e45-a54a-e11ef553af07
                  idempotencyKey: demo:sess_1771456953407_g7p6233d:book:001
      responses:
        '200':
          description: Event accepted and processed
          headers:
            x-request-id:
              $ref: '#/components/headers/XRequestId'
            x-ratelimit-limit:
              $ref: '#/components/headers/XRateLimitLimit'
            x-ratelimit-remaining:
              $ref: '#/components/headers/XRateLimitRemaining'
            x-partner-id:
              $ref: '#/components/headers/XPartnerId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendEventResponse'
              examples:
                shortlist:
                  value:
                    data:
                      sessionId: sess_1771456953407_g7p6233d
                      event:
                        id: evt_1771456966998
                        kind: search_query
                      result:
                        traceId: demo-tenant:partner_api:partner-chat:sess_1771456953407_g7p6233d:evt_1771456966998
                        status: shortlist
                        message:
                          text: I found options matching your request in Seattle.
                        artifacts:
                          shortlist:
                            - optionId: 3d49d4cb-22b1-4963-9280-508fb1190f5c
                              name: Inn at the Market
                              pricePerNight: 276.66
                              totalPrice: 980.67
                              currency: USD
                              refundable: true
                              rating: 4.8
        '400':
          description: Invalid request payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                missing_session_id:
                  value:
                    success: false
                    error: sessionId is required
                    requestId: e8c38dd3-3f92-4521-a4a0-bf5a22d261dc
                missing_idempotency:
                  value:
                    success: false
                    error: idempotencyKey is required for kind=action_book_option
                    requestId: 2a5ea99c-9884-448f-a442-35a883b64b31
        '401':
          $ref: '#/components/responses/MissingApiKeyError'
        '403':
          $ref: '#/components/responses/InvalidApiKeyError'
        '404':
          description: Session not found in this tenant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GatewayErrorResponse'
              examples:
                session_not_found:
                  value:
                    success: false
                    error: Session not found.
                    code: session_not_found
                    details:
                      sessionId: sess_unknown
                    requestId: ca6fc510-87ef-434a-a945-ba19ed0e118f
        '409':
          description: Actor does not match session owner
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                actor_mismatch:
                  value:
                    success: false
                    error: actor.actorId does not match the session owner (partner_user_001).
                    requestId: 6e5d4ecf-2e57-4c63-a8b7-99fd12f8ea7a
        '429':
          $ref: '#/components/responses/RateLimitedError'
        '500':
          description: Unexpected server/proxy error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/GatewayErrorResponse'
                  - $ref: '#/components/schemas/ValidationErrorResponse'

  /api/partner/v1/core-chat/sessions/{sessionId}:
    get:
      tags:
        - Sessions
      summary: Get session snapshot
      description: Return current session state and event history.
      operationId: getPartnerCoreChatSession
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Session snapshot
          headers:
            x-request-id:
              $ref: '#/components/headers/XRequestId'
            x-ratelimit-limit:
              $ref: '#/components/headers/XRateLimitLimit'
            x-ratelimit-remaining:
              $ref: '#/components/headers/XRateLimitRemaining'
            x-partner-id:
              $ref: '#/components/headers/XPartnerId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetSessionResponse'
              examples:
                success:
                  value:
                    data:
                      sessionId: sess_1771456953407_g7p6233d
                      tenantId: demo-tenant
                      actor:
                        actorId: partner_user_001
                      events:
                        - eventId: evt_1771456966998
                          kind: search_query
                          resultStatus: shortlist
                          recordedAt: '2026-02-18T23:22:46.998Z'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GatewayErrorResponse'
              examples:
                session_required:
                  value:
                    success: false
                    error: sessionId is required
                    code: invalid_request
                    details: null
                    requestId: 0fdf6f3b-3c04-47f9-8825-c1189d6ea89b
        '401':
          $ref: '#/components/responses/MissingApiKeyError'
        '403':
          $ref: '#/components/responses/InvalidApiKeyError'
        '404':
          description: Session not found in this tenant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GatewayErrorResponse'
              examples:
                session_not_found:
                  value:
                    success: false
                    error: Session not found.
                    code: session_not_found
                    details:
                      sessionId: sess_unknown
                    requestId: ca6fc510-87ef-434a-a945-ba19ed0e118f
        '429':
          $ref: '#/components/responses/RateLimitedError'
        '500':
          description: Unexpected server/proxy error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/GatewayErrorResponse'
                  - $ref: '#/components/schemas/ValidationErrorResponse'

components:
  securitySchemes:
    PartnerApiKeyHeader:
      type: apiKey
      in: header
      name: x-partner-api-key
      description: Recommended partner API key header.
    PartnerApiKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Alternative format using Authorization: Bearer <partner_api_key>.'
    PartnerApiKeyLegacy:
      type: apiKey
      in: header
      name: api-key
      description: Legacy header support.

  parameters:
    SessionIdPath:
      name: sessionId
      in: path
      required: true
      schema:
        type: string
        minLength: 1
      description: Session ID returned by POST /sessions.

  headers:
    XRequestId:
      description: Request trace ID for support/log correlation.
      schema:
        type: string
    XRateLimitLimit:
      description: Requests-per-minute limit for this partner key.
      schema:
        type: integer
        minimum: 1
    XRateLimitRemaining:
      description: Remaining requests in the current minute window.
      schema:
        type: integer
        minimum: 0
    XPartnerId:
      description: Resolved partner ID for authenticated requests.
      schema:
        type: string

  responses:
    MissingApiKeyError:
      description: Missing partner API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayErrorResponse'
          examples:
            missing_key:
              value:
                success: false
                error: Missing partner API key.
                code: missing_partner_api_key
                details: null
                requestId: d813d7e3-ba0b-4a97-899d-0847590d7560
    InvalidApiKeyError:
      description: Invalid partner API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayErrorResponse'
          examples:
            invalid_key:
              value:
                success: false
                error: Invalid partner API key.
                code: invalid_partner_api_key
                details: null
                requestId: c75e34ff-aa06-4393-ae7d-cf1d31c3af25
    RateLimitedError:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayErrorResponse'
          examples:
            rate_limited:
              value:
                success: false
                error: Exceeded 120 requests per minute
                code: rate_limited
                details:
                  partnerId: acme
                requestId: 5ec2f626-a8df-477f-b6e3-0e5ed96af646

  schemas:
    CreateSessionRequest:
      type: object
      required:
        - actor
      properties:
        actor:
          type: object
          required:
            - actorId
          properties:
            actorId:
              type: string
              minLength: 1
            timezoneOffsetMinutes:
              type: integer
              description: Minutes offset from UTC.
        conversation:
          type: object
          properties:
            id:
              type: string
            channelId:
              type: string
            threadTs:
              type: string
        channel:
          type: object
          properties:
            workspaceId:
              type: string

    CreateSessionResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: '#/components/schemas/SessionData'

    SessionData:
      type: object
      required:
        - sessionId
        - tenantId
        - channel
        - conversation
        - actor
        - createdAt
        - updatedAt
        - events
      properties:
        sessionId:
          type: string
        tenantId:
          type: string
        channel:
          type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - partner_api
            workspaceId:
              type: string
              nullable: true
        conversation:
          type: object
          properties:
            id:
              type: string
            channelId:
              type: string
            threadTs:
              type: string
        actor:
          type: object
          required:
            - actorId
          properties:
            actorId:
              type: string
            timezoneOffsetMinutes:
              type: integer
              nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        events:
          type: array
          items:
            type: object
            additionalProperties: true

    SendEventRequest:
      type: object
      required:
        - sessionId
      properties:
        sessionId:
          type: string
          minLength: 1
        actor:
          type: object
          properties:
            actorId:
              type: string
        kind:
          type: string
        text:
          type: string
        payload:
          type: object
          additionalProperties: true
        idempotencyKey:
          type: string
      description: |
        For write kinds (command_book_by_option_id, action_book_option,
        action_confirm_price_change, action_confirm_payment_card, action_cancel_booking),
        idempotencyKey is required.

    SendEventResponse:
      type: object
      required:
        - data
      properties:
        data:
          type: object
          required:
            - sessionId
            - event
            - result
          properties:
            sessionId:
              type: string
            event:
              type: object
              required:
                - id
                - kind
              properties:
                id:
                  type: string
                kind:
                  type: string
            result:
              type: object
              required:
                - status
                - message
              properties:
                traceId:
                  type: string
                status:
                  type: string
                message:
                  type: object
                  required:
                    - text
                  properties:
                    text:
                      type: string
                artifacts:
                  type: object
                  additionalProperties: true

    GetSessionResponse:
      type: object
      required:
        - data
      properties:
        data:
          type: object
          required:
            - sessionId
            - tenantId
            - actor
            - events
          properties:
            sessionId:
              type: string
            tenantId:
              type: string
            actor:
              type: object
              properties:
                actorId:
                  type: string
            events:
              type: array
              items:
                type: object
                properties:
                  eventId:
                    type: string
                  kind:
                    type: string
                  resultStatus:
                    type: string
                  recordedAt:
                    type: string
                    format: date-time

    GatewayErrorResponse:
      type: object
      required:
        - success
        - error
        - code
        - details
        - requestId
      properties:
        success:
          type: boolean
          enum: [false]
        error:
          type: string
        code:
          type: string
        details:
          nullable: true
          oneOf:
            - type: object
              additionalProperties: true
            - type: string
            - type: array
              items: {}
        requestId:
          type: string

    ValidationErrorResponse:
      type: object
      required:
        - success
        - error
        - requestId
      properties:
        success:
          type: boolean
          enum: [false]
        error:
          type: string
        details:
          nullable: true
          oneOf:
            - type: object
              additionalProperties: true
            - type: string
            - type: array
              items: {}
        requestId:
          type: string
