# Enviar mensagens

Envie texto livre na janela de atendimento ou use um template aprovado, com os anexos e botões previstos no modelo.

### POST /public/v1/messages

> Escolha `text` ou `template`, nunca os dois. Os modelos dos exemplos são ilustrativos: consulte [os templates do seu número](https://patrociniotech.com/documentacao-api/templates.md) e use os nomes e campos retornados.

## Enviar um template

Este exemplo usa um modelo com duas variáveis numeradas: nome da pessoa e número do pedido. Pode ser enviado dentro ou fora da janela de atendimento.

cURL · enviar template

```bash
curl -X POST https://api.patrociniotech.com/public/v1/messages \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: aviso-pedido-8421-v1" \
  -d '{
  "to": "5521999999999",
  "phone_number_id": "SEU_NUMERO_ID",
  "template": "aviso_entrega",
  "language": "pt_BR",
  "variables": [
    "Maria",
    "8421"
  ],
  "client_ref": "pedido-8421"
}'
```

## Resposta de envio aceito

JSON · HTTP 200

```json
{
  "success": true,
  "data": {
    "message_id": "wamid.EXEMPLO",
    "status": "sent",
    "to": "5521999999999",
    "client_ref": "pedido-8421"
  }
}
```

`sent` confirma que a Meta aceitou o envio. Guarde `message_id` e acompanhe `message.status` no [webhook](https://patrociniotech.com/documentacao-api/webhook.md) para confirmar entrega, leitura ou falha.

Guarde também o `to` da resposta: ele identifica o destinatário reconhecido pela Meta. Mantenha o status no seu sistema a partir dos eventos; para conferir uma mensagem já identificada, use a consulta abaixo.

## Consultar um envio sem reenviar

### GET /public/v1/messages/{message_id}/status

Informe o `message_id` devolvido no envio. A consulta lê o estado registrado na Patrocinio Tech, não envia uma mensagem nem consulta o telefone na Meta. Somente mensagens de saída da empresa autenticada são acessíveis.

cURL · consultar status

```bash
curl "https://api.patrociniotech.com/public/v1/messages/wamid.EXEMPLO/status" \
  -H "Authorization: Bearer SUA_CHAVE"
```

JSON · estado registrado

```json
{
  "success": true,
  "data": {
    "message_id": "wamid.EXEMPLO",
    "status": "delivered",
    "client_ref": "pedido-8421",
    "phone_number_id": "SEU_NUMERO_ID",
    "to": "5521999999999",
    "created_at": "2026-11-06T12:00:00Z",
    "message_at": "2026-11-06T12:00:00Z",
    "checked_at": "2026-11-06T12:01:00Z",
    "error": null
  }
}
```

| Campo | Interpretação |
| --- | --- |
| status | sent, delivered, read, played, failed ou unknown. unknown indica ausência de um estado reconhecido; não é confirmação de falha. |
| error | Somente em failed: code numérico da Meta, quando preservado, reason estável da integração e message em português. O texto bruto não é exposto; code pode ser nulo. |
| created\_at / message\_at | Horários UTC do registro e da mensagem/última tentativa. Não são o horário de entrega ou leitura; esses horários não são disponibilizados nesta consulta. |
| checked\_at | Horário desta consulta. Não comprova que chegou um novo evento da Meta nesse instante. |

> O webhook continua sendo o caminho principal. Use esta consulta para conciliar estados pendentes, com intervalo e tentativas limitados; ela também consome a cota de 600 requisições por minuto por chave. Codifique o identificador no caminho da URL com `encodeURIComponent(message_id)`.

`404 message_not_found` pode significar identificador incorreto, registro ainda não persistido, removido pela retenção ou pertencente a outra conta. Não comprova que a mensagem deixou de ser enviada nem autoriza reenvio automático. Sem `message_id`, preserve a operação e a chave de idempotência para recuperar o aceite original.

## Consultar quando o envio ficou sem resposta

### GET /public/v1/messages/status

Se o POST terminou em timeout ou 5xx antes de devolver o `message_id`, consulte com a **Idempotency-Key original**. A leitura encontra inclusive a reserva da tentativa, sem enviar outra mensagem nem liberar a chave.

cURL · consultar pela chave original

```bash
curl "https://api.patrociniotech.com/public/v1/messages/status" \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Idempotency-Key: aviso-pedido-8421-v1"
```

Para uma mensagem já registrada, também é possível consultar por `client_ref`, de até 64 caracteres. Informe apenas uma das opções por chamada. Use uma referência por operação; se houver duas tentativas com a mesma referência, a API retorna `409 ambiguous_client_ref` e não escolhe uma delas.

cURL · consultar pela referência

```bash
curl --get "https://api.patrociniotech.com/public/v1/messages/status" \
  -H "Authorization: Bearer SUA_CHAVE" \
  --data-urlencode "client_ref=pedido-8421"
```

| data.resolution | O que significa |
| --- | --- |
| matched | A mensagem foi localizada no banco. data.message traz message\_id, status, destinatário, horários e error, no mesmo formato da consulta por ID. message\_id pode ser null em uma recusa anterior ao aceite. |
| accepted | Existe um aceite durável da Meta, mas o registro local não foi concluído. message traz o ID original e status sent; isso ainda não confirma entrega. Preserve a operação para reconciliação. |
| unconfirmed | Existe uma reserva sem confirmação do envio. message é null. Não significa failed e não permite criar uma nova chave para enviar de novo. |

JSON · tentativa ainda sem confirmação

```json
{
  "success": true,
  "data": {
    "lookup": "idempotency_key",
    "resolution": "unconfirmed",
    "message": null,
    "checked_at": "2026-11-06T12:01:00Z",
    "retention": {
      "idempotency_days": 2,
      "messages_days": 365,
      "measured_from": "created_at"
    }
  }
}
```

> Atenção: Uma consulta por `client_ref` só encontra tentativas já persistidas. Para timeout antes desse registro, use a chave de idempotência. Em qualquer consulta, `404 message_not_found` não comprova que o envio falhou: pode haver processamento em andamento ou remoção pela retenção.

`retention` informa os prazos configurados no momento da consulta, contados da criação. São dois dias para a reserva e 365 dias para mensagens por padrão; a manutenção é periódica. Mantenha seu histórico de operações e não use o fim desse prazo como autorização para repetir um envio incerto.

## Repetir a operação com segurança

Gere uma `Idempotency-Key` por mensagem e salve-a antes de enviar. Em falha de conexão ou 5xx, repita com **a mesma chave e o mesmo corpo**.

| Resultado | Como agir |
| --- | --- |
| 200 · idempotent\_replay: true | A resposta é de uma operação já aceita. Use o message\_id retornado; a repetição não dispara outro envio. |
| 409 · idempotency\_in\_flight | A operação está em andamento ou sem confirmação. Aguarde e repita com a mesma chave. Se persistir, confira os eventos antes de iniciar outro envio. |
| 409 · idempotency\_conflict | A chave pertence a outro conteúdo. Confira a operação original; use outra chave somente para uma nova mensagem intencional. |
| 409 · idempotency\_legacy\_unverified | O registro antigo não permite comparar o conteúdo. Verifique o envio original e os eventos antes de outra tentativa. |

> Atenção: Não gere outra chave para contornar uma tentativa sem confirmação. A reserva não é liberada automaticamente após cinco minutos. A proteção dura pelo período de retenção; mantenha o histórico da operação também no seu sistema.

Dados recusados antes do envio podem ser corrigidos. Para tratar limites e indisponibilidade, use a política de [novas tentativas](https://patrociniotech.com/documentacao-api/erros.md).

## Enviar texto livre

O contato precisa ter escrito para o mesmo número da empresa nas últimas 24 horas. Confirme a [janela de atendimento](https://patrociniotech.com/documentacao-api/janela.md) quando necessário; ela não determina a gratuidade.

cURL · enviar texto livre

```bash
curl -X POST https://api.patrociniotech.com/public/v1/messages \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: texto-pedido-8421-v1" \
  -d '{
  "to": "5521999999999",
  "phone_number_id": "SEU_NUMERO_ID",
  "text": "Seu pedido saiu para entrega.",
  "client_ref": "pedido-8421"
}'
```

## Enviar um template com PDF

O cabeçalho `DOCUMENT` exige o arquivo em cada envio. Este exemplo combina um PDF, variáveis nomeadas e um botão de link dinâmico.

cURL · enviar template com PDF

```bash
curl -X POST https://api.patrociniotech.com/public/v1/messages \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: bilhete-pedido-8421-v1" \
  -d '{
  "to": "5521999999999",
  "phone_number_id": "SEU_NUMERO_ID",
  "template": "entrega_pedido_documento",
  "language": "pt_BR",
  "variable_names": [
    "pedido",
    "valor"
  ],
  "variables": [
    "8421",
    "R$ 495,75"
  ],
  "header_media": {
    "type": "document",
    "link": "https://arquivos.suaempresa.com/bilhetes/8421.pdf",
    "filename": "Bilhete 8421.pdf"
  },
  "button_url_param": "8421",
  "button_url_index": 0,
  "client_ref": "pedido-8421"
}'
```

> A Meta precisa acessar o link sem uma sessão de navegador. Use HTTPS e mantenha o arquivo disponível durante o envio. A amostra da aprovação não substitui o documento do pedido; para enviar sem PDF, selecione um template sem esse cabeçalho.

## Enviar um código de autenticação

Use um modelo `AUTHENTICATION` com botão OTP. A API preenche o corpo e o botão nativo com o mesmo `otp_code`. O índice suportado é `0`.

cURL · autenticação

```bash
curl -X POST https://api.patrociniotech.com/public/v1/messages \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: verificacao-operacao-1234-v1" \
  -d '{
  "to": "5521999999999",
  "phone_number_id": "SEU_NUMERO_ID",
  "template": "codigo_verificacao",
  "language": "pt_BR",
  "otp_code": "123456",
  "otp_index": 0,
  "client_ref": "operacao-1234"
}'
```

> Atenção: Gere o código no seu servidor e valide prazo, destinatário, operação, uso único e tentativas. O texto de expiração do template não invalida o código nem apaga a mensagem. Veja [validade do código e prazo de entrega](https://patrociniotech.com/documentacao-api/templates.md).

## Referência dos campos

Envie somente os campos documentados. Nomes desconhecidos, inclusive dentro de `header_media` e `pix_order`, retornam `422 invalid_request`. Os detalhes indicam o campo a corrigir; ele não é ignorado para prosseguir com valores padrão.

### Destinatário e conteúdo

| Campo | Regra |
| --- | --- |
| to | Obrigatório. Telefone internacional, com DDI e DDD, somente dígitos. Ex.: 5521999999999 (Brasil) ou 351912345678 (Portugal). O envio não acrescenta o país automaticamente. |
| phone\_number\_id | ID do seu número conectado. Sem ele, a API usa o número padrão da conta. |
| text | Texto livre de até 4.096 caracteres. Exige janela aberta e não pode ser combinado com campos de template. |
| template | Nome do modelo aprovado. Use em vez de text. |
| language | Idioma do modelo. Padrão: pt\_BR. |
| reply\_to\_message\_id | Opcional. ID da mensagem recebida que será citada na resposta. |

### Variáveis e cabeçalho

| Campo | Regra |
| --- | --- |
| variables | Um valor por variável do corpo. Até 20 valores de 1.024 caracteres; a quantidade exigida vem do modelo. |
| variable\_names | Nomes associados aos valores em variables, para modelos NAMED. Use a ordem da listagem ou mantenha cada par nome/valor correspondente. |
| header\_media | Obrigatório se o modelo exigir mídia. Objeto com type (document, image ou video), link HTTP(S) válido, sem usuário/senha ou espaços, e filename opcional para documento. |
| header\_text | Até 200 caracteres. Obrigatório se o cabeçalho de texto tiver uma variável; omita para cabeçalho fixo ou de mídia. |

### Botões e autenticação

| Campo | Regra |
| --- | --- |
| button\_url\_param | Valor da parte variável de um botão de link. Até 200 caracteres; a API aceita um link dinâmico por template. |
| button\_url\_index | Posição do botão de link na lista, começando em zero. Padrão: 0. |
| coupon\_code / coupon\_index | Código de até 15 caracteres e posição do botão de cupom COPY\_CODE. Não use para autenticação. |
| otp\_code | Código de autenticação de até 15 caracteres, sem espaços ou caracteres de controle. variables pode ser omitido. |
| otp\_index | Para autenticação, use 0 ou omita. Não combine OTP com anexo, cupom, link dinâmico ou PIX. |
| pix\_order | Pedido para um template de cobrança, com botão ORDER\_DETAILS. Veja o exemplo abaixo. |

Valores de variáveis não aceitam quebras de linha, tabulações ou mais de quatro espaços consecutivos. Nenhum valor é cortado para caber: a API informa o erro para você corrigir.

## Marketing, consentimento e saída da lista

A API permite enviar um template `MARKETING` a um contato com aceite `pending` ou sem cadastro local. Isso não registra consentimento como `accepted`. Conserve no seu sistema a origem da lista e a evidência de que a pessoa espera essa comunicação.

Uma recusa de promoções em qualquer número da mesma empresa, ou um bloqueio no número de envio, impede novos envios de marketing com `422 marketing_not_allowed`. Não há parâmetro para ignorar essa exclusão. A consulta de [janela e preferência](https://patrociniotech.com/documentacao-api/janela.md) permite conferir o bloqueio antes; a API verifica novamente ao enviar.

> Nas campanhas do painel, incluir contatos com aceite pendente exige confirmação de risco. Essa opção não transforma pendência em aceite e não inclui quem pediu para sair. A API de envio individual não recebe essa opção de campanha.

Uma saída de promoções não impede um aviso legítimo de pedido com template `UTILITY` ou um código solicitado com `AUTHENTICATION`. Use a categoria correspondente ao conteúdo; mudar a categoria não é uma forma de reenviar a promoção recusada.

## Relacionar o envio ao seu pedido

`client_ref` é opcional, tem até 64 caracteres e volta nos eventos de status. Use um identificador único da operação, como `pedido-8421-entrega-v1`, para consultá-la depois. Ele ajuda na conciliação, mas não substitui a `Idempotency-Key` nem impede envios duplicados.

Guarde também `message_id` e `phone_number_id`: um pedido pode ter várias mensagens e mais de um número de envio.

## Cobrança PIX

Disponível para template de detalhes do pedido e conta com pagamentos habilitados na Meta. Os valores são inteiros JSON em centavos; strings, decimais e booleanos são recusados. A API confere a soma dos itens e da taxa, sem arredondar valores.

### Ver exemplo de cobrança e campos de pagamento

cURL · cobrança PIX

```bash
curl -X POST https://api.patrociniotech.com/public/v1/messages \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: cobranca-pedido-8421-v1" \
  -d '{
  "to": "5521999999999",
  "phone_number_id": "SEU_NUMERO_ID",
  "template": "cobranca_emissao",
  "language": "pt_BR",
  "pix_order": {
    "reference_id": "PED-8421",
    "pix_code": "CODIGO_PIX_COMPLETO_GERADO_PELO_SEU_PSP",
    "merchant_name": "Sua Empresa",
    "key": "CHAVE_PIX_DA_EMPRESA",
    "key_type": "EVP",
    "items": [
      {
        "name": "Emissão de passagem",
        "amount": 49575,
        "quantity": 1
      }
    ],
    "tax": 0
  },
  "client_ref": "pedido-8421"
}'
```

| Em pix\_order | Uso |
| --- | --- |
| reference\_id | Referência da cobrança no seu sistema. Até 64 caracteres. |
| pix\_code | Copia e cola completo gerado pelo seu PSP para esta cobrança. Não use o texto ilustrativo acima. |
| merchant\_name / key / key\_type | Nome do recebedor, chave PIX e tipo: CNPJ, CPF, EMAIL, PHONE ou EVP. |
| items | Até 30 itens com name, amount unitário em centavos e quantity. |
| tax / total\_amount | tax é opcional, com padrão 0. Se total\_amount for informado, deve ser igual a Σ(amount × quantity) + tax. |
| Limite numérico | Cada valor e o total calculado devem caber em 9.007.199.254.740.991 centavos, limite de inteiro seguro da integração. Isso não substitui os limites da Meta ou do seu PSP. |
| goods\_type / retailer\_id | goods\_type: digital-goods (padrão) ou physical-goods. retailer\_id é opcional em cada item; sem ele, a posição identifica o item. |

## Validar um telefone

Se o cadastro contém apenas DDD e telefone, informe o país em `country` (ISO de duas letras) nesta consulta antes de enviar. Para um telefone já internacional, use `+` e DDI, ou envie somente os dígitos e omita `country`. Não presuma que todos os clientes usam o DDI 55.

### POST /public/v1/validate

cURL · validar formato

```bash
curl -X POST https://api.patrociniotech.com/public/v1/validate \
  -H "Authorization: Bearer SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{"to": "(21) 99999-9999", "country": "BR"}'
```

Use o `to` normalizado quando `data.valid` for `true`. Essa consulta valida o formato; não confirma existência no WhatsApp nem autorização para envio.

> Atenção: `valid=true` não significa que a mensagem será entregue. Um telefone digitado errado pode ter formato válido. A Cloud API não oferece uma consulta prévia para confirmar se o destinatário tem WhatsApp.

Após enviar, guarde `message_id` e `client_ref`. Considere a entrega confirmada apenas ao receber `message.status` com `delivered` ou `read`. O aceite inicial `sent` ainda pode terminar em `failed`.

Se chegar `error.reason=recipient_unreachable` com `error.code=131026`, registre a falha e confira o telefone com o cliente por outro canal. Esse código não comprova ausência de WhatsApp. Evite repetições automáticas e variações do número sem confirmação.

---

Fonte: https://patrociniotech.com/documentacao-api/mensagens
Índice para IA: https://patrociniotech.com/documentacao-api/llms.txt
