openapi: "3.1.0"
info:
  title: MiniApp — Hooks de Saida
  description: >
    Hooks de saida do nosso aplicativo para o externo (Acloud → MiniApp).
    Enviados como requisicoes POST para o webhook_url configurado para o bot.

    O campo `webhook_url` do bot so pode ser editado via API generica pelo aplicativo
    externo — a UI do Contactcenter nao exibe este campo para evitar edicoes acidentais
    pelo operador.
  version: "2.0.0"

x-retry-policy:
  max_retries: 3
  strategy: exponential backoff
  delays_ms: [500, 1000, 2000]

x-expected-response:
  success_codes: [200, 201, 202]
  description: Qualquer resposta 2xx e considerada bem-sucedida. Codigos que nao sejam 2xx sao registrados como erro de envio.

webhooks:

  message.new.personal:
    post:
      summary: Envio de mensagem do gestor
      description: >
        A URL e configurada nas configuracoes do bot (campo webhook_url).
        Nosso sistema envia um POST com corpo JSON quando um evento ocorre.
      x-headers:
        Content-Type: application/json
        Accept: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - message.new.personal
                payload:
                  $ref: '#/components/schemas/MessageNewPayload'
            examples:
              message_new:
                summary: Envio de mensagem do gestor
                value:
                  method: message.new.personal
                  payload:
                    channel_id: bot_token_abc123
                    inner_message_id: "9001"
                    external_chat_id: chat_789
                    text: Bom dia! Seu pedido #42 foi enviado.
                    timestamp: 1710752400
                    event_id: '550e8400-e29b-41d4-a716-446655440000:79000'
                    attachments: []
              message_new_with_attachments:
                summary: Envio de mensagem com anexos
                value:
                  method: message.new.personal
                  payload:
                    channel_id: bot_token_abc123
                    inner_message_id: "9002"
                    external_chat_id: chat_789
                    text: Anexando a fatura
                    timestamp: 1710752500
                    event_id: '6ba7b810-9dad-11d1-80b4-00c04fd430c8:79000'
                    attachments:
                      - id: "555"
                        type: file
                        url: https://crm.example.com/files/555/download
                        filename: invoice.pdf
                        size: 102400
      responses:
        "200":
          description: Mensagem aceita com sucesso

  chat.init.personal:
    post:
      summary: Inicializacao de novo chat
      description: >
        Enviado quando um gestor contata um usuario pela primeira vez e o chat ainda nao existe.
        Apos receber este hook, o aplicativo externo deve enviar o evento de entrada
        message.new.personal com uma mensagem confirmando a criacao do chat.
      x-headers:
        Content-Type: application/json
        Accept: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - chat.init.personal
                payload:
                  $ref: '#/components/schemas/ChatInitPayload'
            examples:
              chat_init:
                summary: Inicializacao de chat com usuario
                value:
                  method: chat.init.personal
                  payload:
                    channel_id: bot_token_abc123
                    to:
                      email: joao@example.com
                      name: Joao Silva
                      phone: "+79001234567"
                      other: null
                    message:
                      text: Bom dia! Como posso ajudar?
                    event_id: '7c9e6679-7425-40de-944b-e07fc1f90ae7:79000'
      responses:
        "200":
          description: Solicitacao de inicializacao de chat aceita

  bot.deactivated:
    post:
      summary: Bot desativado
      description: >
        Enviado quando o bot MiniApp e desativado no lado do Acloud. A razao e indicada no
        campo reason: manual (desativacao manual), auto_unreachable (automatica por
        inacessibilidade), subscription_expired (vencimento da assinatura).
        Fire-and-forget: a acao ja foi realizada no lado do Acloud.
      x-headers:
        Content-Type: application/json
        Accept: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - bot.deactivated
                payload:
                  $ref: '#/components/schemas/BotDeactivatedPayload'
            examples:
              bot_deactivated_manual:
                summary: Bot desativado manualmente
                value:
                  method: bot.deactivated
                  payload:
                    channel_id: bot_token_abc123
                    reason: manual
      responses:
        "200":
          description: Notificacao aceita

  bot.deleted:
    post:
      summary: Bot excluido
      description: >
        Enviado quando o bot MiniApp e excluido no lado do Acloud.
        Fire-and-forget: a acao ja foi realizada no lado do Acloud.
      x-headers:
        Content-Type: application/json
        Accept: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - bot.deleted
                payload:
                  $ref: '#/components/schemas/BotDeletedPayload'
            examples:
              bot_deleted:
                summary: Bot excluido
                value:
                  method: bot.deleted
                  payload:
                    channel_id: bot_token_abc123
      responses:
        "200":
          description: Notificacao aceita

  bot.activated:
    post:
      summary: Bot ativado
      description: >
        Enviado **apenas** quando o bot passa do estado inativo para o ativo
        (`was_active=false → is_active=true`) para um bot **existente**.
        Ao criar um novo bot ativo, o hook **NAO e enviado** —
        o aplicativo externo ainda nao sabe da existencia de tal bot.
        Fire-and-forget: a acao ja foi realizada no lado do Acloud.
      x-headers:
        Content-Type: application/json
        Accept: application/json
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - bot.activated
                payload:
                  $ref: '#/components/schemas/BotActivatedPayload'
            examples:
              bot_activated:
                summary: Bot ativado
                value:
                  method: bot.activated
                  payload:
                    channel_id: bot_token_abc123
      responses:
        "200":
          description: Notificacao aceita

components:
  schemas:

    OutgoingEvent:
      type: object
      required:
        - method
        - payload
      properties:
        method:
          type: string
          enum:
            - message.new.personal
            - chat.init.personal
            - bot.deactivated
            - bot.deleted
            - bot.activated
          description: Tipo de evento
        payload:
          oneOf:
            - $ref: '#/components/schemas/MessageNewPayload'
            - $ref: '#/components/schemas/ChatInitPayload'
            - $ref: '#/components/schemas/BotDeactivatedPayload'
            - $ref: '#/components/schemas/BotDeletedPayload'
            - $ref: '#/components/schemas/BotActivatedPayload'
          discriminator:
            propertyName: method

    # ─── message.new.personal ─────────────────────────────────────────────────

    MessageNewPayload:
      type: object
      description: Envio de mensagem do gestor ao usuario via aplicativo externo
      required:
        - channel_id
        - inner_message_id
        - external_chat_id
        - text
        - timestamp
        - event_id
      properties:
        channel_id:
          type: string
          description: Token do bot (bot_token) — ID de integracao no lado do aplicativo externo
          example: bot_token_abc123
        inner_message_id:
          type: string
          description: >
            ID da mensagem no nosso sistema.
            O aplicativo externo deve retorna-lo no evento message.completed.personal.
          example: "9001"
        external_chat_id:
          type: string
          description: ID do chat no sistema externo para o qual a mensagem e enviada
          example: chat_789
        text:
          type: string
          description: Texto da mensagem
          example: Bom dia! Seu pedido #42 foi enviado.
        timestamp:
          type: integer
          description: Unix timestamp do momento de envio
          example: 1710752400
        event_id:
          type: string
          description: >
            Identificador opaco do evento (ate 60 caracteres). O aplicativo externo deve armazenar
            este valor como esta e retorna-lo sem alteracoes no campo event_id do evento error se
            nao conseguiu processar o hook. A estrutura do campo e um detalhe interno do Acloud e
            pode mudar sem aviso; nao analise nem valide o conteudo.
          example: '550e8400-e29b-41d4-a716-446655440000:79000'
        attachments:
          type: array
          default: []
          items:
            $ref: '#/components/schemas/OutgoingAttachmentObject'
          description: >
            Arquivos anexados a mensagem. O aplicativo externo deve fazer o download de cada
            arquivo pela url e entrega-lo ao destinatario.

    # ─── chat.init.personal ───────────────────────────────────────────────────

    ChatInitPayload:
      type: object
      description: >
        Inicializacao de um novo chat pessoal com um usuario.
        Usado no primeiro contato quando external_chat_id ainda nao e conhecido.
      required:
        - channel_id
        - to
        - message
        - event_id
      properties:
        channel_id:
          type: string
          description: Token do bot (bot_token) — ID de integracao no lado do aplicativo externo
          example: bot_token_abc123
        to:
          $ref: '#/components/schemas/To'
        message:
          type: object
          description: Primeira mensagem no chat sendo criado
          required:
            - text
          properties:
            text:
              type: string
              description: Texto da primeira mensagem
              example: Bom dia! Como posso ajudar?
        event_id:
          type: string
          description: >
            Identificador opaco do evento (ate 60 caracteres). O aplicativo externo deve armazenar
            este valor como esta e retorna-lo sem alteracoes no campo event_id do evento error se
            nao conseguiu processar o hook. A estrutura do campo e um detalhe interno do Acloud e
            pode mudar sem aviso; nao analise nem valide o conteudo.
          example: '7c9e6679-7425-40de-944b-e07fc1f90ae7:79000'

    # ─── bot.deactivated ───────────────────────────────────────────────────

    BotDeactivatedPayload:
      type: object
      description: >
        Notificacao de desativacao do bot. Fire-and-forget — sem correlacao com error prevista.
      required:
        - channel_id
        - reason
      properties:
        channel_id:
          type: string
          description: Token do bot (bot_token) — ID de integracao no lado do aplicativo externo
          example: bot_token_abc123
        reason:
          type: string
          description: >
            Razao de desativacao: manual — desativacao manual pelo usuario,
            auto_unreachable — automatica por inacessibilidade do aplicativo externo,
            subscription_expired — vencimento da assinatura da conta
          enum:
            - manual
            - auto_unreachable
            - subscription_expired
          example: manual

    # ─── bot.deleted ─────────────────────────────────────────────────────

    BotDeletedPayload:
      type: object
      description: >
        Notificacao de exclusao do bot. Fire-and-forget — sem correlacao com error prevista.
      required:
        - channel_id
      properties:
        channel_id:
          type: string
          description: Token do bot (bot_token) — ID de integracao no lado do aplicativo externo
          example: bot_token_abc123

    # ─── bot.activated ───────────────────────────────────────────────────

    BotActivatedPayload:
      type: object
      description: >
        Notificacao de reativacao de um bot previamente desativado.
        Fire-and-forget — sem correlacao com error prevista.
      required:
        - channel_id
      properties:
        channel_id:
          type: string
          description: Token do bot (bot_token) — ID de integracao no lado do aplicativo externo
          example: bot_token_abc123

    # ─── Shared types ─────────────────────────────────────────────────────────

    To:
      type: object
      description: Dados do destinatario para inicializacao do chat
      properties:
        email:
          type: ["string", "null"]
          description: Email do usuario
        name:
          type: ["string", "null"]
          description: Nome do usuario
        phone:
          type: ["string", "null"]
          description: Numero de telefone do usuario
        other:
          type: ["string", "null"]
          description: Identificador adicional do usuario no sistema externo

    OutgoingAttachmentObject:
      type: object
      description: >
        Metadados do anexo de saida. O aplicativo externo deve fazer o download do arquivo
        pela url fornecida e entrega-lo ao destinatario.
      required:
        - id
        - type
        - url
        - filename
      properties:
        id:
          type: string
          description: ID do arquivo no sistema Acloud.
        type:
          type: string
          enum: [photo, video, audio, file]
          description: Tipo de anexo determinado pelo mime do arquivo.
        url:
          type: string
          description: >
            Link publico de uso unico para download do arquivo do Acloud.
            Valido por ate 7 dias (para destinatarios iOS) ou sem expiracao (por UUID).
        filename:
          type: string
          description: Nome do arquivo com extensao.
        size:
          type: integer
          description: Tamanho do arquivo em bytes.
        metadata:
          type: ["object", "null"]
          description: Metadados arbitrarios (opcional).
