> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pilotstatus.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Origens de anúncio (CTWA)

> Lista as mensagens recebidas pelo número vinculado que vieram de um clique em anúncio ou post do Click-to-WhatsApp, mais recentes primeiro. Na prática só números da API oficial (Meta) têm origem de anúncio: o bloco `referral` é um campo do webhook da Cloud API.

A Meta envia a origem **apenas na primeira mensagem** da conversa e nunca a repete, então cada item aqui equivale a uma conversa que nasceu daquele anúncio.

`referral.sourceId` é o **id do anúncio (ou do post)** da Meta, exposto como chave opaca de agrupamento. Não há nome de campanha nem de conjunto aqui, e isso não é omissão: ler o objeto do anúncio (`GET /{ad_id}?fields=id,name,adset{id,name},campaign{id,name}`) exige a permissão `ads_read` na conta de anúncios do anunciante, e o token de usuário de sistema por trás de um número conectado carrega apenas `whatsapp_business_management` e `whatsapp_business_messaging`. Para resolver os nomes, chame a Marketing API da Meta com um token autorizado naquela conta, usando este `sourceId`.

Privacidade (PII): numa linha redigida a identidade do anúncio sobrevive (`sourceId`, `sourceType`) e `ctwaClid`, `headline` e `body` voltam nulos, com `redacted: true` — id de anúncio identifica um criativo, nunca uma pessoa, então a atribuição continua funcionando num número RELAY_ONLY em vez de devolver nada.

**Requer key escopada a número.**

O objeto `referral` também traz os nomes RESOLVIDOS do anúncio — `adName`, `adsetId`, `adsetName`, `campaignId`, `campaignName` — e mais `namesResolvedAt`.

⚠️ Esses seis voltam **null** enquanto o anunciante não tiver compartilhado aquela conta de anúncios com o portfólio empresarial da Pilot Status como parceiro. Nome nulo é estado SUPORTADO, não erro: a conversa continua contada e o `sourceId` continua vindo.

Nenhum endpoint resolve nome sob demanda — a resolução é assíncrona, fora do caminho da requisição, então consultar nunca dispara chamada à Marketing API e um null pode virar nome minutos depois sem você fazer nada. O `namesResolvedAt` é o que torna isso observável: null significa "ainda não resolvido", enquanto data preenchida com nomes nulos significa "perguntamos e a Meta não devolveu" (anúncio apagado, ou compartilhamento ausente).



## OpenAPI

````yaml openapi.pt.json GET /v1/referrals
openapi: 3.1.0
info:
  title: API Pilot Status
  version: 1.0.0
  license:
    name: Pilot Status Terms of Service
    url: https://pilotstatus.com.br/terms
  description: >-
    API REST pública do Pilot Status. Autentique com o header `x-api-key:
    ps_...` (ou `x-api-key-id`). Base URL: https://pilotstatus.com.br
servers:
  - url: https://pilotstatus.com.br
security:
  - apiKey: []
  - apiKeyId: []
paths:
  /v1/referrals:
    get:
      tags:
        - Conversations
      summary: Listar origens de anúncio (CTWA)
      description: >-
        Lista as mensagens recebidas pelo número vinculado que vieram de um
        clique em anúncio ou post do Click-to-WhatsApp, mais recentes primeiro.
        Na prática só números da API oficial (Meta) têm origem de anúncio: o
        bloco `referral` é um campo do webhook da Cloud API.


        A Meta envia a origem **apenas na primeira mensagem** da conversa e
        nunca a repete, então cada item aqui equivale a uma conversa que nasceu
        daquele anúncio.


        `referral.sourceId` é o **id do anúncio (ou do post)** da Meta, exposto
        como chave opaca de agrupamento. Não há nome de campanha nem de conjunto
        aqui, e isso não é omissão: ler o objeto do anúncio (`GET
        /{ad_id}?fields=id,name,adset{id,name},campaign{id,name}`) exige a
        permissão `ads_read` na conta de anúncios do anunciante, e o token de
        usuário de sistema por trás de um número conectado carrega apenas
        `whatsapp_business_management` e `whatsapp_business_messaging`. Para
        resolver os nomes, chame a Marketing API da Meta com um token autorizado
        naquela conta, usando este `sourceId`.


        Privacidade (PII): numa linha redigida a identidade do anúncio sobrevive
        (`sourceId`, `sourceType`) e `ctwaClid`, `headline` e `body` voltam
        nulos, com `redacted: true` — id de anúncio identifica um criativo,
        nunca uma pessoa, então a atribuição continua funcionando num número
        RELAY_ONLY em vez de devolver nada.


        **Requer key escopada a número.**


        O objeto `referral` também traz os nomes RESOLVIDOS do anúncio —
        `adName`, `adsetId`, `adsetName`, `campaignId`, `campaignName` — e mais
        `namesResolvedAt`.


        ⚠️ Esses seis voltam **null** enquanto o anunciante não tiver
        compartilhado aquela conta de anúncios com o portfólio empresarial da
        Pilot Status como parceiro. Nome nulo é estado SUPORTADO, não erro: a
        conversa continua contada e o `sourceId` continua vindo.


        Nenhum endpoint resolve nome sob demanda — a resolução é assíncrona,
        fora do caminho da requisição, então consultar nunca dispara chamada à
        Marketing API e um null pode virar nome minutos depois sem você fazer
        nada. O `namesResolvedAt` é o que torna isso observável: null significa
        "ainda não resolvido", enquanto data preenchida com nomes nulos
        significa "perguntamos e a Meta não devolveu" (anúncio apagado, ou
        compartilhamento ausente).
      operationId: get_referrals
      parameters:
        - name: sourceId
          in: query
          required: false
          description: Filtra por um único id de anúncio/post.
          schema:
            type: string
            description: (string)
          example: '120249828053880703'
        - name: sourceType
          in: query
          required: false
          description: 'Filtra por tipo de origem: "ad" ou "post".'
          schema:
            type: string
            description: (string ("ad" | "post"))
          example: ad
        - name: startDate
          in: query
          required: false
          description: Início do período (sobre providerTimestamp). Deve ser ≤ endDate.
          schema:
            type: string
            description: (string (ISO 8601))
          example: '2026-08-01T00:00:00Z'
        - name: endDate
          in: query
          required: false
          description: Fim do período (sobre providerTimestamp).
          schema:
            type: string
            description: (string (ISO 8601))
          example: '2026-08-17T23:59:59Z'
        - name: page
          in: query
          required: false
          description: Página (padrão 1).
          schema:
            type: string
            description: (integer (≥1))
          example: '1'
        - name: pageSize
          in: query
          required: false
          description: Itens por página (padrão 30, máx 100).
          schema:
            type: string
            description: (integer (1–100))
          example: '30'
      responses:
        '200':
          description: Listar origens de anúncio
          content:
            application/json:
              example:
                referrals:
                  - id: cm_01HZX...
                    conversationId: conv_01HZX...
                    direction: INBOUND
                    providerKind: META
                    externalMessageId: wamid.HBgNNTU0Mj...
                    messageType: text
                    text: Oi, vi o anúncio
                    providerTimestamp: '2026-08-16T12:00:00.000Z'
                    referral:
                      sourceId: '120249828053880703'
                      sourceType: ad
                      sourceUrl: https://www.instagram.com/p/DcJhrlpA3Pl/
                      headline: SALE MM DESIGN
                      body: Seu ambiente pode ficar ainda mais incrível
                      mediaType: video
                      imageUrl: null
                      videoUrl: https://video.example/v.mp4
                      thumbnailUrl: https://thumb.example/t.jpg
                      ctwaClid: ARAaZ1x...
                      adName: Ads 01 - Vídeo dos 70%
                      adsetId: '120249828053990703'
                      adsetName: '[IG] [LL1% IG + VÍDEOS] - 35 a 50'
                      campaignId: '120249677595590703'
                      campaignName: '[CD-01] [WHATSAPP] - MM Design - Sale 70%'
                      namesResolvedAt: '2026-08-17T21:04:00.000Z'
                  - id: cm_def456
                    conversationId: conv_01HZX...
                    direction: INBOUND
                    providerKind: META
                    externalMessageId: wamid.HBgNNTU0Mj...2
                    messageType: text
                    text: quero saber o preço
                    providerTimestamp: '2026-08-16T12:00:00.000Z'
                    referral:
                      sourceId: '120249828075420703'
                      sourceType: ad
                      sourceUrl: https://www.instagram.com/p/DcJhrlpA3Pl/
                      headline: MM DESIGN — Outlet
                      body: Seu ambiente pode ficar ainda mais incrível
                      mediaType: video
                      imageUrl: null
                      videoUrl: https://video.example/v.mp4
                      thumbnailUrl: https://thumb.example/t.jpg
                      ctwaClid: ARAaZ1x...
                      adName: null
                      adsetId: null
                      adsetName: null
                      campaignId: null
                      campaignName: null
                      namesResolvedAt: null
                total: 2
                page: 1
                pageSize: 30
                totalPages: 1
        '400':
          description: Tipo de origem inválido
          content:
            application/json:
              example:
                error: sourceType must be "ad" or "post"
                code: INVALID_SOURCE_TYPE
        '401':
          description: Header `x-api-key` / `x-api-key-id` ausente ou inválido
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
              example:
                error: Unauthorized
        '403':
          description: Chave com escopo de tenant usada em endpoint com escopo de número
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
              example:
                error: Tenant-scoped keys cannot call number endpoints
                code: TENANT_SCOPE_NOT_ALLOWED
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: Sua chave de API ps_
    apiKeyId:
      type: apiKey
      in: header
      name: x-api-key-id
      description: Id da chave de API (alternativa ao x-api-key)

````