> ## 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.

# Registar o endpoint do Flow na Meta

> Regista o NOSSO proxy como `endpoint_uri` deste Flow na Meta — o ato deliberado que o `PUT` neste mesmo recurso se recusa a fazer. **Sem isto o `data_exchange` é inalcançável**: a Meta recusa publicar um Flow cujo modelo de routing precisa de endpoint, com *"Publishing without specifying 'endpoint_uri' is forbidden"*.

⛔ É um verbo diferente e não um efeito colateral do `PUT` porque os dois atos têm sujeitos diferentes. Guardar um destino é o tenant a descrever o webhook DELE; isto é nós a dizer à META para encaminhar o Flow por nós. Fundir os dois faria com que um tenant que corre o próprio endpoint de Flow perdesse todas as trocas na próxima vez que corrigisse uma gralha numa URL.

⚠️ O corpo é OPCIONAL — ao contrário do `PUT`, este verbo não tem campo obrigatório, portanto sem corpo, string vazia e `{}` são todos aceites. Um corpo truncado continua a ser recusado (400 `FLOW_BODY_INVALID`), e `confirmOverwrite` é o único campo aceite.

⛔ `confirmOverwrite` não é formalidade. O `endpoint_uri` atual é lido AO VIVO do Graph — não de `metaEndpointUri`, que uma sincronia horária escreve e que por isso está muda sobre um URI registado na última hora. Se o Flow já aponta para outro sítio, registar leva TODAS as trocas de quem responde hoje, por isso o padrão é 409 `FLOW_ENDPOINT_URI_WOULD_OVERWRITE` — cujo corpo traz um QUARTO campo de topo, `currentEndpointUri`, nomeando o endpoint que seria deslocado. O nosso nunca é ecoado: embute o token de caminho do endpoint do número. Um não-booleano é recusado e nunca convertido (400 `FLOW_ENDPOINT_CONFIRM_INVALID`), porque `"false"` lido como verdadeiro assumiria um endpoint vivo num pedido cujo autor acreditava ter recusado.

Idempotente: um Flow que já aponta para nós responde 200 sem escrita no Graph, e `metaEndpointUri` é atualizado de qualquer forma. Um número sem par de chaves de endpoint é recusado com 422 `FLOW_ENDPOINT_NUMBER_HAS_NO_KEY` — registar mesmo assim diz à Meta para cifrar para um par de chaves que não existe, e todas as trocas do Flow publicado dariam 421. Permissão `flows:manage`.

**Exige chave com escopo de número.** Uma chave de tenant precisa nomear o número no header `x-whatsapp-number-id`, senão recebe 403 `TENANT_SCOPE_NOT_ALLOWED`.



## OpenAPI

````yaml openapi.pt.json POST /v1/flows/{id}/endpoint
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/flows/{id}/endpoint:
    post:
      tags:
        - Flows
      summary: Registar o endpoint do Flow na Meta
      description: >-
        Regista o NOSSO proxy como `endpoint_uri` deste Flow na Meta — o ato
        deliberado que o `PUT` neste mesmo recurso se recusa a fazer. **Sem isto
        o `data_exchange` é inalcançável**: a Meta recusa publicar um Flow cujo
        modelo de routing precisa de endpoint, com *"Publishing without
        specifying 'endpoint_uri' is forbidden"*.


        ⛔ É um verbo diferente e não um efeito colateral do `PUT` porque os dois
        atos têm sujeitos diferentes. Guardar um destino é o tenant a descrever
        o webhook DELE; isto é nós a dizer à META para encaminhar o Flow por
        nós. Fundir os dois faria com que um tenant que corre o próprio endpoint
        de Flow perdesse todas as trocas na próxima vez que corrigisse uma
        gralha numa URL.


        ⚠️ O corpo é OPCIONAL — ao contrário do `PUT`, este verbo não tem campo
        obrigatório, portanto sem corpo, string vazia e `{}` são todos aceites.
        Um corpo truncado continua a ser recusado (400 `FLOW_BODY_INVALID`), e
        `confirmOverwrite` é o único campo aceite.


        ⛔ `confirmOverwrite` não é formalidade. O `endpoint_uri` atual é lido AO
        VIVO do Graph — não de `metaEndpointUri`, que uma sincronia horária
        escreve e que por isso está muda sobre um URI registado na última hora.
        Se o Flow já aponta para outro sítio, registar leva TODAS as trocas de
        quem responde hoje, por isso o padrão é 409
        `FLOW_ENDPOINT_URI_WOULD_OVERWRITE` — cujo corpo traz um QUARTO campo de
        topo, `currentEndpointUri`, nomeando o endpoint que seria deslocado. O
        nosso nunca é ecoado: embute o token de caminho do endpoint do número.
        Um não-booleano é recusado e nunca convertido (400
        `FLOW_ENDPOINT_CONFIRM_INVALID`), porque `"false"` lido como verdadeiro
        assumiria um endpoint vivo num pedido cujo autor acreditava ter
        recusado.


        Idempotente: um Flow que já aponta para nós responde 200 sem escrita no
        Graph, e `metaEndpointUri` é atualizado de qualquer forma. Um número sem
        par de chaves de endpoint é recusado com 422
        `FLOW_ENDPOINT_NUMBER_HAS_NO_KEY` — registar mesmo assim diz à Meta para
        cifrar para um par de chaves que não existe, e todas as trocas do Flow
        publicado dariam 421. Permissão `flows:manage`.


        **Exige chave com escopo de número.** Uma chave de tenant precisa nomear
        o número no header `x-whatsapp-number-id`, senão recebe 403
        `TENANT_SCOPE_NOT_ALLOWED`.
      operationId: post_flows_id_endpoint
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            O id **local** do Flow — o campo `id` que `GET /v1/flows` devolve,
            nunca o `metaFlowId`.
          schema:
            type: string
          example: cmf1a2b3c4d5e6f7g8h9i0j1
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                confirmOverwrite:
                  type: boolean
                  description: >-
                    Consentimento para deslocar um `endpoint_uri` que não é
                    nosso. Tem de ser um booleano de verdade — a string
                    `"false"` é recusada, nunca convertida. Desnecessário quando
                    a Meta não tem `endpoint_uri`, ou já tem o nosso.
                  example: true
            example:
              confirmOverwrite: true
      responses:
        '200':
          description: >-
            A Meta passa a apontar este Flow para o nosso proxy.
            `metaEndpointUri` é atualizado a partir do que acabou de ser
            escrito, não do espelho horário. Sem `secret`: registar não cunha
            nada
          content:
            application/json:
              example:
                flowId: cmf1a2b3c4d5e6f7g8h9i0j1
                url: https://hooks.acme.com/flows/data-exchange
                hasSecret: true
                endpointUri: >-
                  https://pilotstatus.com.br/api/flows/endpoint/AbC123.../1122334455
                metaEndpointUri: >-
                  https://pilotstatus.com.br/api/flows/endpoint/AbC123.../1122334455
                drift: false
                numberHasKey: true
                numberKeyUploadedAt: '2026-09-01T18:04:00.000Z'
                warnings: []
        '400':
          description: >-
            `FLOW_ENDPOINT_CONFIRM_INVALID`, `FLOW_BODY_INVALID`,
            `FLOW_UNKNOWN_FIELDS`, `FLOW_NUMBER_FROM_KEY`, ou uma recusa da Meta
            repassada com a mensagem e o código dela
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: Portuguese half
                  errorEN:
                    type: string
                    description: English half
                  code:
                    type: string
              example:
                error: confirmOverwrite deve ser um booleano (true ou false).
                errorEN: confirmOverwrite must be a boolean (true or false).
                code: FLOW_ENDPOINT_CONFIRM_INVALID
        '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,
            ou o papel da chave não tem a permissão
          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
        '404':
          description: >-
            Nenhum Flow com esse id dentro da WABA da própria chave. Nunca 403:
            um Flow de outro tenant é indistinguível de um que não existe, de
            propósito — um 403 confirmaria o id alheio a quem o adivinhou
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: Portuguese half
                  errorEN:
                    type: string
                    description: English half
                  code:
                    type: string
              example:
                error: Flow não encontrado para o número desta chave.
                errorEN: Flow not found for this key's number.
                code: FLOW_NOT_FOUND
        '409':
          description: >-
            A Meta já aponta este Flow para um endpoint que não é o nosso. Nada
            no pedido está malformado — o que bloqueia é o ESTADO na Meta, e
            reenviar o mesmo corpo continua a bater nele até o chamador decidir
            assumir. O quarto campo de topo `currentEndpointUri` nomeia o
            endpoint que seria deslocado; o nosso não é ecoado, porque embute o
            token de caminho do endpoint do número
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: Portuguese half
                  errorEN:
                    type: string
                    description: English half
                  code:
                    type: string
                  currentEndpointUri:
                    type: string
                    description: >-
                      O `endpoint_uri` que a Meta tem hoje, lido ao vivo do
                      Graph. Presente só neste erro
              example:
                error: >-
                  A Meta já aponta este Flow para outro endpoint. Registar o
                  nosso passaria TODAS as trocas deste Flow para a Pilot Status.
                  Reenvie com confirmOverwrite para assumir.
                errorEN: >-
                  Meta already points this Flow at another endpoint. Registering
                  ours would take EVERY exchange of this Flow over to Pilot
                  Status. Re-send with confirmOverwrite to take it over.
                code: FLOW_ENDPOINT_URI_WOULD_OVERWRITE
                currentEndpointUri: https://flows.acme.com/data-exchange
        '422':
          description: >-
            `FLOW_ENDPOINT_NUMBER_HAS_NO_KEY` (o número não tem par de chaves de
            endpoint, logo não existe URL para registar),
            `FLOW_REQUIRES_META_NUMBER` (o número da chave não é Meta, ou não
            tem WABA associada) ou `FLOW_NUMBER_WABA_MISMATCH`
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: Portuguese half
                  errorEN:
                    type: string
                    description: English half
                  code:
                    type: string
              example:
                error: >-
                  Este número ainda não tem chave de endpoint de Flow, por isso
                  não existe URL para registar na Meta. Gere a chave do número
                  primeiro.
                errorEN: >-
                  This number has no Flow endpoint key yet, so there is no URL
                  to register at Meta. Generate the number's key first.
                code: FLOW_ENDPOINT_NUMBER_HAS_NO_KEY
        '429':
          description: Limite de taxa excedido
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
              example:
                error: Too many requests
        '500':
          description: Erro interno. Nunca carrega a mensagem interna — essa fica no log
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: Portuguese half
                  errorEN:
                    type: string
                    description: English half
                  code:
                    type: string
              example:
                error: Erro interno do servidor.
                errorEN: Internal server error.
                code: INTERNAL_ERROR
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)

````