openapi: 3.1.0
info:
  title: Conchi Agent API
  version: 2026-05-01
  description: Contrato publico V1 para enviar turns conversacionales desde clientes externos y recibir callbacks asincronos con la respuesta final del agente.
servers:
  - url: https://staging-api.conchi.ai/api/v1
    description: Staging API.
  - url: https://api.conchi.ai/api/v1
    description: Produccion API.
security:
  - ExternalClientBearerAuth: []
paths:
  /external-agent/turns:
    post:
      operationId: createExternalAgentTurn
      summary: Enviar un mensaje conversacional de un cliente externo
      description: Acepta un turn de texto para procesamiento asincrono. La respuesta final se entrega mediante webhook.
      security:
        - ExternalClientBearerAuth: []
      parameters:
        - name: Conchi-API-Version
          in: header
          required: false
          schema:
            type: string
            example: "2026-05-01"
          description: Fecha opcional del contrato V1.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExternalAgentTurnRequest"
            examples:
              accountScopedProductSearch:
                summary: Busqueda con cuenta externa
                value:
                  externalAccountId: pharmacy-001
                  externalEndCustomerId: customer-789
                  message:
                    type: text
                    text: Busco ibuprofeno 400
                  correlationId: turn-search-001
                  requestId: turn-search-001
                  capabilityHint: product_search
              accountlessClient:
                summary: Cliente externo sin subcuentas
                value:
                  externalEndCustomerId: app-user-789
                  message:
                    type: text
                    text: Busco ibuprofeno 400
                  correlationId: turn-search-002
                  capabilityHint: product_search
              reservationCreate:
                summary: Creacion de reserva con idempotencia
                value:
                  externalAccountId: pharmacy-001
                  externalEndCustomerId: customer-789
                  message:
                    type: text
                    text: Si, reservalo
                  correlationId: turn-reservation-001
                  requestId: turn-reservation-001
                  capabilityHint: reservation_create
                  idempotencyKey: reservation-customer-789-001
      responses:
        "202":
          description: Turn aceptado para procesamiento asincrono.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExternalAgentTurnAccepted"
              examples:
                accepted:
                  value:
                    sessionId: 00000000-0000-0000-0000-000000000001
                    turnId: 00000000-0000-0000-0000-000000000002
                    requestId: turn-search-001
                    status: queued
        "400":
          $ref: "#/components/responses/Error"
        "401":
          $ref: "#/components/responses/Error"
        "403":
          $ref: "#/components/responses/Error"
        "500":
          $ref: "#/components/responses/Error"
webhooks:
  agentFinalResponse:
    post:
      summary: Callback de respuesta final del agente
      description: Conchi envia este evento al webhook configurado para el cliente externo o para el override de externalAccountId.
      parameters:
        - name: Authorization
          in: header
          required: false
          schema:
            type: string
            example: Bearer callback-secret
          description: Presente cuando el modo de callback es bearer.
        - name: X-Conchi-Event-Id
          in: header
          required: true
          schema:
            type: string
          description: Identificador unico del evento de callback. Debe usarse para deduplicacion.
        - name: X-Conchi-Timestamp
          in: header
          required: true
          schema:
            type: string
          description: Unix timestamp en segundos usado para HMAC y replay protection.
        - name: X-Conchi-Signature-256
          in: header
          required: false
          schema:
            type: string
            example: sha256=0123456789abcdef
          description: Firma HMAC-SHA256 en modo hmac_sha256. La entrada firmada es "{event_id}.{timestamp}.{raw_body}".
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExternalAgentFinalResponseCallback"
            examples:
              answered:
                summary: Respuesta final contestada
                value:
                  apiVersion: v1
                  eventVersion: "2026-05-01"
                  type: conchi.agent.final_response
                  deliveryTarget: external_agent_callback
                  createdAt: "2026-05-01T10:00:00.000Z"
                  externalClientId: 00000000-0000-0000-0000-000000000010
                  externalAccountId: pharmacy-001
                  externalEndCustomerId: customer-789
                  sessionId: 00000000-0000-0000-0000-000000000001
                  turnId: 00000000-0000-0000-0000-000000000002
                  correlationId: turn-search-001
                  status: answered
                  message: "He encontrado estas opciones:\n\n1) Ibuprofeno 400 mg\n3.50 EUR\nDisponible"
              escalated:
                summary: Respuesta con escalado a humano
                value:
                  apiVersion: v1
                  eventVersion: "2026-05-01"
                  type: conchi.agent.final_response
                  deliveryTarget: external_agent_callback
                  createdAt: "2026-05-01T10:00:00.000Z"
                  externalClientId: 00000000-0000-0000-0000-000000000010
                  externalAccountId: pharmacy-001
                  externalEndCustomerId: customer-789
                  sessionId: 00000000-0000-0000-0000-000000000001
                  turnId: 00000000-0000-0000-0000-000000000003
                  correlationId: turn-human-001
                  status: escalated
                  message: Para atenderte mejor en este tema, voy a conectarte con una persona del equipo.
      responses:
        "2XX":
          description: Callback aceptado por el cliente externo. Conchi considera entregado cualquier status 2xx.
components:
  securitySchemes:
    ExternalClientBearerAuth:
      type: http
      scheme: bearer
      bearerFormat: external_client_api_key
  responses:
    Error:
      description: Error de entrada.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          examples:
            invalidPayload:
              value:
                error: INVALID_PAYLOAD
                message: INVALID_PAYLOAD
                details:
                  - path: message.text
                    message: String must contain at least 1 character(s)
            invalidAuth:
              value:
                error: EXTERNAL_CLIENT_AUTH_INVALID
                message: Invalid external client credentials
  schemas:
    ExternalAgentCapability:
      type: string
      enum:
        - product_search
        - reservation_create
        - human_escalation
    ExternalAgentTurnRequest:
      type: object
      additionalProperties: true
      required:
        - externalEndCustomerId
        - message
      properties:
        externalAccountId:
          type: string
          minLength: 1
          maxLength: 160
          description: Cuenta, farmacia, workspace o scope por debajo del cliente externo. Si se omite y la integracion lo permite, Conchi lo normaliza a default.
        externalEndCustomerId:
          type: string
          minLength: 1
          maxLength: 160
          description: Usuario final de la conversacion.
        message:
          $ref: "#/components/schemas/ExternalAgentTextMessage"
        correlationId:
          type: string
          maxLength: 160
          description: Id de correlacion del cliente externo devuelto en callbacks cuando se envia.
        requestId:
          type: string
          maxLength: 160
          description: Id de request del cliente externo. Si se omite, Conchi usa correlationId o genera uno.
        idempotencyKey:
          type: string
          maxLength: 180
          description: Clave de idempotencia recomendada para creacion de reservas.
        capabilityHint:
          $ref: "#/components/schemas/ExternalAgentCapability"
        metadata:
          type: object
          additionalProperties: true
          description: Metadatos pequenos de integracion. Evitar PII innecesaria.
    ExternalAgentTextMessage:
      type: object
      additionalProperties: false
      required:
        - type
        - text
      properties:
        type:
          type: string
          const: text
        text:
          type: string
          minLength: 1
          maxLength: 8000
    ExternalAgentTurnAccepted:
      type: object
      additionalProperties: false
      required:
        - sessionId
        - turnId
        - requestId
        - status
      properties:
        sessionId:
          type: string
          format: uuid
        turnId:
          type: string
          format: uuid
        requestId:
          type: string
        status:
          type: string
          const: queued
    ExternalAgentFinalResponseCallback:
      type: object
      additionalProperties: true
      required:
        - apiVersion
        - eventVersion
        - type
        - deliveryTarget
        - createdAt
        - externalClientId
        - externalAccountId
        - externalEndCustomerId
        - sessionId
        - turnId
        - status
        - message
      properties:
        apiVersion:
          type: string
          const: v1
        eventVersion:
          type: string
          example: "2026-05-01"
        type:
          type: string
          const: conchi.agent.final_response
        deliveryTarget:
          type: string
          const: external_agent_callback
        createdAt:
          type: string
          format: date-time
        externalClientId:
          type: string
          description: Cliente externo autenticado que origino la conversacion.
        externalAccountId:
          type: string
          description: Cuenta externa normalizada. Puede ser default.
        externalEndCustomerId:
          type: string
        sessionId:
          type: string
        turnId:
          type: string
        correlationId:
          type: string
        status:
          type: string
          enum:
            - answered
            - escalated
            - failed
            - needs_more_info
        message:
          type: string
          description: Texto final que debe mostrar el cliente externo al usuario final.
        structured:
          type: object
          additionalProperties: true
          description: Datos estructurados opcionales. No son obligatorios en V1.
    ErrorResponse:
      type: object
      additionalProperties: true
      properties:
        error:
          type: string
          examples:
            - INVALID_PAYLOAD
            - EXTERNAL_AGENT_AUTH_REQUIRED
            - EXTERNAL_CLIENT_AUTH_INVALID
            - EXTERNAL_CLIENT_INACTIVE
            - EXTERNAL_ACCOUNT_INACTIVE
        message:
          type: string
        details:
          type: array
          items:
            type: object
            additionalProperties: true
