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

# Como enviar mensagens para BSUID (WhatsApp oficial)

> Envie mensagens para um BSUID (Business-Scoped User ID) pela API oficial (WABA) quando o telefone do usuário está oculto. Exemplos em cURL, Node.js, Python e Go.

Este guia mostra como enviar mensagens para um **BSUID** (Business-Scoped User ID), o identificador sem telefone que a Meta usa no WhatsApp oficial (WABA). O envio usa o mesmo endpoint `POST /v1/wa/messages`, trocando apenas o valor do campo `recipient`.

## O que é um BSUID

BSUID é a sigla de **Business-Scoped User ID**. É um identificador que a Meta gera para representar um usuário do WhatsApp sem expor o número de telefone dele.

Ele existe por causa do rollout de **nomes de usuário (usernames)** do WhatsApp, previsto para 2026. Quando um usuário escolhe conversar por username, ou opta por manter o número oculto, a sua empresa deixa de receber o telefone e passa a receber um BSUID no lugar. Esse identificador permite continuar a conversa normalmente, só que o telefone real nunca é revelado.

O BSUID é **escopado por portfolio de negócio** (business portfolio). O mesmo usuário aparece com um BSUID diferente para cada portfolio, então um BSUID só serve dentro do portfolio que o recebeu (veja [Limitações e erros](#limitações-e-erros)).

<Note>
  O BSUID é **exclusivo do canal oficial (WABA)**. No canal não oficial (QR code), o identificador análogo é o **LID**, que segue pelo fluxo normal de JID. Um BSUID enviado para uma instância não oficial é rejeitado com o erro `waba_bsuid_requires_waba`.
</Note>

## Formato

O BSUID tem duas formas:

| Tipo                                               | Formato                                  | Exemplo                       |
| -------------------------------------------------- | ---------------------------------------- | ----------------------------- |
| **Padrão**                                         | código do país + `.` + identificador     | `US.13491208655302741918`     |
| **Parent** (negócios gerenciados entre portfolios) | código do país + `.ENT.` + identificador | `US.ENT.11815799212886844830` |

Regras do formato:

* O prefixo é o **código de país ISO 3166 alpha-2** (duas letras, como `US`, `BR`, `PT`).
* Em seguida vem um ponto (`.`).
* BSUIDs **parent** inserem o segmento `ENT` (também seguido de ponto) entre o código do país e o identificador.
* O identificador final tem até 128 caracteres alfanuméricos e é **opaco**: trate-o como uma string sem significado interno, sem alterar.

## Como enviar

O envio é idêntico ao de uma mensagem WABA comum. Você usa o mesmo endpoint `POST /v1/wa/messages` e a mesma assinatura de requisição. A única diferença é que o campo `recipient` recebe o BSUID em vez de um número de telefone. A Zapster detecta o formato de BSUID automaticamente e monta o payload da Cloud API da Meta com o campo correto.

Antes de começar, você precisa de uma [instância WABA conectada](/pt-BR/v1/guides/connect-waba-instance). Em todos os exemplos, troque `YOUR_API_TOKEN` pelo seu token de API e `YOUR_INSTANCE_ID` pelo ID da instância WABA. O BSUID de exemplo (`US.13491208655302741918`) representa o destinatário; use o BSUID real que chegou no seu webhook.

<Note>
  Como acontece com qualquer mensagem livre em WABA, texto, mídia e botões só são entregues dentro da **janela de conversa de 24 horas**. Fora da janela, use um **template** aprovado (veja mais abaixo). O detalhamento completo está em [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages).
</Note>

### Texto simples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.zapsterapi.com/v1/wa/messages \
    -H "Authorization: Bearer YOUR_API_TOKEN" \
    -H "X-Instance-ID: YOUR_INSTANCE_ID" \
    -H "Content-Type: application/json" \
    -d '{
      "recipient": "US.13491208655302741918",
      "text": "Olá! Seu pedido foi confirmado."
    }'
  ```

  ```javascript Node.js (axios) theme={null}
  const axios = require('axios')

  const response = await axios.post(
    'https://api.zapsterapi.com/v1/wa/messages',
    {
      recipient: 'US.13491208655302741918',
      text: 'Olá! Seu pedido foi confirmado.',
    },
    {
      headers: {
        Authorization: 'Bearer YOUR_API_TOKEN',
        'X-Instance-ID': 'YOUR_INSTANCE_ID',
      },
    },
  )

  console.log(response.data.message_id)
  ```

  ```javascript Node.js (fetch) theme={null}
  const response = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
    body: JSON.stringify({
      recipient: 'US.13491208655302741918',
      text: 'Olá! Seu pedido foi confirmado.',
    }),
    headers: {
      Authorization: 'Bearer YOUR_API_TOKEN',
      'Content-Type': 'application/json',
      'X-Instance-ID': 'YOUR_INSTANCE_ID',
    },
    method: 'POST',
  })

  const data = await response.json()
  console.log(data.message_id)
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.zapsterapi.com/v1/wa/messages",
      headers={
          "Authorization": "Bearer YOUR_API_TOKEN",
          "X-Instance-ID": "YOUR_INSTANCE_ID",
      },
      json={
          "recipient": "US.13491208655302741918",
          "text": "Olá! Seu pedido foi confirmado.",
      },
  )

  print(response.json()["message_id"])
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  	"strings"
  )

  func main() {
  	body := strings.NewReader(`{
  		"recipient": "US.13491208655302741918",
  		"text": "Olá! Seu pedido foi confirmado."
  	}`)

  	req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
  	req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
  	req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
  	req.Header.Set("Content-Type", "application/json")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer res.Body.Close()

  	data, _ := io.ReadAll(res.Body)
  	fmt.Println(string(data))
  }
  ```
</CodeGroup>

### Mídia (imagem, vídeo ou documento)

Envie a mídia por URL pública ou base64 no campo `media`. O tipo é detectado automaticamente a partir do arquivo.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.zapsterapi.com/v1/wa/messages \
    -H "Authorization: Bearer YOUR_API_TOKEN" \
    -H "X-Instance-ID: YOUR_INSTANCE_ID" \
    -H "Content-Type: application/json" \
    -d '{
      "recipient": "US.13491208655302741918",
      "media": {
        "url": "https://exemplo.com/imagem.jpg",
        "caption": "Confira o catálogo de julho"
      }
    }'
  ```

  ```javascript Node.js (axios) theme={null}
  const axios = require('axios')

  await axios.post(
    'https://api.zapsterapi.com/v1/wa/messages',
    {
      media: {
        caption: 'Confira o catálogo de julho',
        url: 'https://exemplo.com/imagem.jpg',
      },
      recipient: 'US.13491208655302741918',
    },
    {
      headers: {
        Authorization: 'Bearer YOUR_API_TOKEN',
        'X-Instance-ID': 'YOUR_INSTANCE_ID',
      },
    },
  )
  ```

  ```javascript Node.js (fetch) theme={null}
  await fetch('https://api.zapsterapi.com/v1/wa/messages', {
    body: JSON.stringify({
      media: {
        caption: 'Confira o catálogo de julho',
        url: 'https://exemplo.com/imagem.jpg',
      },
      recipient: 'US.13491208655302741918',
    }),
    headers: {
      Authorization: 'Bearer YOUR_API_TOKEN',
      'Content-Type': 'application/json',
      'X-Instance-ID': 'YOUR_INSTANCE_ID',
    },
    method: 'POST',
  })
  ```

  ```python Python theme={null}
  import requests

  requests.post(
      "https://api.zapsterapi.com/v1/wa/messages",
      headers={
          "Authorization": "Bearer YOUR_API_TOKEN",
          "X-Instance-ID": "YOUR_INSTANCE_ID",
      },
      json={
          "recipient": "US.13491208655302741918",
          "media": {
              "url": "https://exemplo.com/imagem.jpg",
              "caption": "Confira o catálogo de julho",
          },
      },
  )
  ```

  ```go Go theme={null}
  package main

  import (
  	"net/http"
  	"strings"
  )

  func main() {
  	body := strings.NewReader(`{
  		"recipient": "US.13491208655302741918",
  		"media": {
  			"url": "https://exemplo.com/imagem.jpg",
  			"caption": "Confira o catálogo de julho"
  		}
  	}`)

  	req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
  	req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
  	req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
  	req.Header.Set("Content-Type", "application/json")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	res.Body.Close()
  }
  ```
</CodeGroup>

### Botões interativos

As regras de botão em WABA valem também para BSUID: até 3 botões `reply`, ou exatamente 1 botão `url`, sem misturar os dois tipos. A matriz completa está em [Mensagem com botões](/pt-BR/v1/guides/messages-with-buttons).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.zapsterapi.com/v1/wa/messages \
    -H "Authorization: Bearer YOUR_API_TOKEN" \
    -H "X-Instance-ID: YOUR_INSTANCE_ID" \
    -H "Content-Type: application/json" \
    -d '{
      "recipient": "US.13491208655302741918",
      "text": "Deseja confirmar o agendamento de amanhã?",
      "buttons": [
        { "id": "confirm", "label": "Confirmar", "type": "reply" },
        { "id": "reschedule", "label": "Remarcar", "type": "reply" },
        { "id": "cancel", "label": "Cancelar", "type": "reply" }
      ]
    }'
  ```

  ```javascript Node.js (axios) theme={null}
  const axios = require('axios')

  await axios.post(
    'https://api.zapsterapi.com/v1/wa/messages',
    {
      buttons: [
        { id: 'confirm', label: 'Confirmar', type: 'reply' },
        { id: 'reschedule', label: 'Remarcar', type: 'reply' },
        { id: 'cancel', label: 'Cancelar', type: 'reply' },
      ],
      recipient: 'US.13491208655302741918',
      text: 'Deseja confirmar o agendamento de amanhã?',
    },
    {
      headers: {
        Authorization: 'Bearer YOUR_API_TOKEN',
        'X-Instance-ID': 'YOUR_INSTANCE_ID',
      },
    },
  )
  ```

  ```javascript Node.js (fetch) theme={null}
  await fetch('https://api.zapsterapi.com/v1/wa/messages', {
    body: JSON.stringify({
      buttons: [
        { id: 'confirm', label: 'Confirmar', type: 'reply' },
        { id: 'reschedule', label: 'Remarcar', type: 'reply' },
        { id: 'cancel', label: 'Cancelar', type: 'reply' },
      ],
      recipient: 'US.13491208655302741918',
      text: 'Deseja confirmar o agendamento de amanhã?',
    }),
    headers: {
      Authorization: 'Bearer YOUR_API_TOKEN',
      'Content-Type': 'application/json',
      'X-Instance-ID': 'YOUR_INSTANCE_ID',
    },
    method: 'POST',
  })
  ```

  ```python Python theme={null}
  import requests

  requests.post(
      "https://api.zapsterapi.com/v1/wa/messages",
      headers={
          "Authorization": "Bearer YOUR_API_TOKEN",
          "X-Instance-ID": "YOUR_INSTANCE_ID",
      },
      json={
          "recipient": "US.13491208655302741918",
          "text": "Deseja confirmar o agendamento de amanhã?",
          "buttons": [
              {"id": "confirm", "label": "Confirmar", "type": "reply"},
              {"id": "reschedule", "label": "Remarcar", "type": "reply"},
              {"id": "cancel", "label": "Cancelar", "type": "reply"},
          ],
      },
  )
  ```

  ```go Go theme={null}
  package main

  import (
  	"net/http"
  	"strings"
  )

  func main() {
  	body := strings.NewReader(`{
  		"recipient": "US.13491208655302741918",
  		"text": "Deseja confirmar o agendamento de amanhã?",
  		"buttons": [
  			{ "id": "confirm", "label": "Confirmar", "type": "reply" },
  			{ "id": "reschedule", "label": "Remarcar", "type": "reply" },
  			{ "id": "cancel", "label": "Cancelar", "type": "reply" }
  		]
  	}`)

  	req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
  	req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
  	req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
  	req.Header.Set("Content-Type", "application/json")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	res.Body.Close()
  }
  ```
</CodeGroup>

### Template (fora da janela de 24h)

Templates funcionam com BSUID, com uma exceção importante: **templates de autenticação one-tap, zero-tap e copy-code não são suportados** para BSUID e são rejeitados pela Meta com o erro `131062` (veja [Limitações e erros](#limitações-e-erros)). Templates de utility e marketing, e templates de autenticação com código por texto, funcionam normalmente.

O objeto `template` é um espelho do formato da Meta. Detalhes de `components`, variáveis posicionais e nomeadas estão em [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages#template-fora-da-janela-de-24h).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.zapsterapi.com/v1/wa/messages \
    -H "Authorization: Bearer YOUR_API_TOKEN" \
    -H "X-Instance-ID: YOUR_INSTANCE_ID" \
    -H "Content-Type: application/json" \
    -d '{
      "recipient": "US.13491208655302741918",
      "template": {
        "name": "confirmacao_pedido",
        "language": "pt_BR",
        "components": [
          {
            "type": "body",
            "parameters": [
              { "type": "text", "text": "João" }
            ]
          }
        ]
      }
    }'
  ```

  ```javascript Node.js (axios) theme={null}
  const axios = require('axios')

  await axios.post(
    'https://api.zapsterapi.com/v1/wa/messages',
    {
      recipient: 'US.13491208655302741918',
      template: {
        components: [
          {
            parameters: [{ text: 'João', type: 'text' }],
            type: 'body',
          },
        ],
        language: 'pt_BR',
        name: 'confirmacao_pedido',
      },
    },
    {
      headers: {
        Authorization: 'Bearer YOUR_API_TOKEN',
        'X-Instance-ID': 'YOUR_INSTANCE_ID',
      },
    },
  )
  ```

  ```javascript Node.js (fetch) theme={null}
  await fetch('https://api.zapsterapi.com/v1/wa/messages', {
    body: JSON.stringify({
      recipient: 'US.13491208655302741918',
      template: {
        components: [
          {
            parameters: [{ text: 'João', type: 'text' }],
            type: 'body',
          },
        ],
        language: 'pt_BR',
        name: 'confirmacao_pedido',
      },
    }),
    headers: {
      Authorization: 'Bearer YOUR_API_TOKEN',
      'Content-Type': 'application/json',
      'X-Instance-ID': 'YOUR_INSTANCE_ID',
    },
    method: 'POST',
  })
  ```

  ```python Python theme={null}
  import requests

  requests.post(
      "https://api.zapsterapi.com/v1/wa/messages",
      headers={
          "Authorization": "Bearer YOUR_API_TOKEN",
          "X-Instance-ID": "YOUR_INSTANCE_ID",
      },
      json={
          "recipient": "US.13491208655302741918",
          "template": {
              "name": "confirmacao_pedido",
              "language": "pt_BR",
              "components": [
                  {
                      "type": "body",
                      "parameters": [{"type": "text", "text": "João"}],
                  }
              ],
          },
      },
  )
  ```

  ```go Go theme={null}
  package main

  import (
  	"net/http"
  	"strings"
  )

  func main() {
  	body := strings.NewReader(`{
  		"recipient": "US.13491208655302741918",
  		"template": {
  			"name": "confirmacao_pedido",
  			"language": "pt_BR",
  			"components": [
  				{
  					"type": "body",
  					"parameters": [{ "type": "text", "text": "João" }]
  				}
  			]
  		}
  	}`)

  	req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
  	req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
  	req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
  	req.Header.Set("Content-Type", "application/json")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	res.Body.Close()
  }
  ```
</CodeGroup>

## De onde vem o BSUID

Você não inventa um BSUID: ele **chega até você pelos webhooks de entrada**. A Zapster normaliza todo webhook antes de entregar, então você nunca lida com os campos crus da Meta. O contato sempre chega no mesmo formato, com `id`, `phone_number` e `bsuid`.

Em um evento `message.received`, o contato do cliente vem em `sender` (e, em conversas de um para um, também em `recipient`, que espelha o `sender`). O campo `id` é o identificador primário e segue uma regra simples: **telefone quando existe, BSUID quando não existe**.

* **Telefone visível:** `phone_number` traz o número e `bsuid` traz o BSUID (a Meta envia os dois). O `id` aponta para o `phone_number`.
* **Telefone oculto (usuário com privacidade):** `phone_number` é `null`, `bsuid` traz o BSUID e o `id` assume o valor do BSUID.

Veja o `message.received` nos dois cenários. Em ambos, o `id` do contato é o valor que você usa no `recipient` para responder dentro da janela de 24 horas:

<AccordionGroup>
  <Accordion title="Telefone oculto (apenas BSUID)">
    `phone_number` é `null`, `bsuid` traz o BSUID e o `id` assume o valor do BSUID.

    ```json theme={null}
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "type": "message.received",
      "created_at": "2026-07-25T14:22:07.000Z",
      "data": {
        "id": "wamid.HBgLMTU1NTU1NTU1NTUVAgARGBI5RjZ...",
        "type": "text",
        "sender": {
          "id": "US.13491208655302741918",
          "phone_number": null,
          "name": "Maria",
          "bsuid": "US.13491208655302741918",
          "profile_picture": null,
          "type": "chat"
        },
        "recipient": {
          "id": "US.13491208655302741918",
          "phone_number": null,
          "name": "Maria",
          "bsuid": "US.13491208655302741918",
          "profile_picture": null,
          "type": "chat"
        },
        "content": { "text": "Oi, cadê meu pedido?" },
        "sent_at": "2026-07-25T14:22:07.000Z"
      }
    }
    ```
  </Accordion>

  <Accordion title="Telefone visível (telefone + BSUID)">
    `phone_number` e `bsuid` vêm preenchidos, e o `id` aponta para o `phone_number`.

    ```json theme={null}
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "type": "message.received",
      "created_at": "2026-07-25T14:22:07.000Z",
      "data": {
        "id": "wamid.HBgLMTU1NTU1NTU1NTUVAgARGBI5RjZ...",
        "type": "text",
        "sender": {
          "id": "5511999999999",
          "phone_number": "5511999999999",
          "name": "Maria",
          "bsuid": "US.13491208655302741918",
          "profile_picture": null,
          "type": "chat"
        },
        "recipient": {
          "id": "5511999999999",
          "phone_number": "5511999999999",
          "name": "Maria",
          "bsuid": "US.13491208655302741918",
          "profile_picture": null,
          "type": "chat"
        },
        "content": { "text": "Oi, cadê meu pedido?" },
        "sent_at": "2026-07-25T14:22:07.000Z"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

Nos eventos de status (`message.sent`, `message.delivered`, `message.read`), o contato do cliente vem em `recipient` no mesmo formato, então o BSUID aparece em `recipient.bsuid` (e no `recipient.id` quando o telefone está oculto).

O fluxo prático é: o cliente manda mensagem para o seu número, você recebe o webhook, lê o `id` do contato (que já é o BSUID quando o telefone está oculto), guarda esse valor e usa ele no `recipient` do `POST /v1/wa/messages` para responder dentro da janela de 24 horas. Veja [Eventos disponíveis](/pt-BR/v1/webhooks/available-events) para o catálogo de webhooks.

## Limitações e erros

Quando o payload usa um recurso que a Cloud API não suporta com BSUID, a Zapster rejeita a requisição na hora com um erro `400`, sem descartar nada silenciosamente.

| Código                                  | Quando acontece                                                                                                   | Como resolver                                                                                                                                 |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `waba_bsuid_requires_waba`              | BSUID no `recipient` de uma instância **não oficial**                                                             | BSUID só funciona no canal oficial (WABA). Para instâncias não oficiais, use o número de telefone (o análogo do BSUID no não oficial é o LID) |
| `waba_bsuid_message_type_not_supported` | Template de autenticação **one-tap**, **zero-tap** ou **copy-code** enviado para um BSUID (erro `131062` da Meta) | Esses templates de autenticação exigem um número de telefone. Use um destinatário com telefone, ou escolha outro tipo de mensagem             |

Além disso, lembre do escopo por portfolio:

* **O BSUID é escopado por portfolio de negócio.** Um BSUID recebido em um portfolio **não** vale em outro. Se você tentar enviar para um BSUID a partir de uma instância ligada a outro portfolio, a Meta rejeita o envio. Sempre responda usando a mesma instância (mesmo portfolio) que recebeu aquele BSUID.

## Boas práticas

* **Aceite e normalize as maiúsculas do prefixo.** O código do país e o segmento `ENT` são estruturais e canonicamente maiúsculos (`US`, `US.ENT.`). A Zapster normaliza um BSUID digitado como `us.ent.<id>` para a forma que a Meta emite, então um valor em minúsculo no `recipient` também funciona.
* **Nunca altere o identificador.** A parte depois do prefixo é opaca e pode ser sensível a maiúsculas e minúsculas. Preserve-a byte a byte: não faça uppercase, trim de zeros ou qualquer transformação.
* **Guarde o BSUID canônico para correlação.** Armazene o BSUID na forma canônica (prefixo maiúsculo, identificador intacto) para casar com o valor que chega nos webhooks e manter o histórico do contato consistente. Vale lembrar que, quando o usuário troca de número, a Meta gera um novo BSUID para ele, então trate o BSUID como identificador do contato naquele portfolio, não como algo eterno.

## Próximos passos

* [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages) para o guia completo de texto, mídia, botões e templates
* [WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial) para entender a diferença entre BSUID (oficial) e LID (não oficial)
* [Eventos disponíveis](/pt-BR/v1/webhooks/available-events) para receber o BSUID nos webhooks de entrada
