Mensagens
Um endpoint só, para os dois casos: texto livre dentro da janela de 24h e template aprovado fora dela. O que decide é o corpo que você manda.
/public/v1/messagesTexto livre (janela de 24h) (link para esta seção)
Vale quando o contato escreveu para você nas últimas 24 horas. É a regra da Meta, não nossa, e existe para você não virar canal de spam.
curl -X POST https://api.patrociniotech.com/public/v1/messages \
-H "Authorization: Bearer ptk_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "5521999999999",
"text": "Seu pedido saiu para entrega.",
"client_ref": "pedido-8421"
}'Template aprovado (fora da janela) (link para esta seção)
É o caso de campanha, cobrança e aviso que parte de você. Crie e aprove o template no painel, em Templates, e mande o nome dele aqui. variables preenche {{1}}, {{2}} e assim por diante, na ordem.
curl -X POST https://api.patrociniotech.com/public/v1/messages \
-H "Authorization: Bearer ptk_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "5521999999999",
"template": "aviso_entrega",
"language": "pt_BR",
"variables": ["Maria", "8421"],
"client_ref": "pedido-8421"
}'Template com anexo (bilhete, comprovante, nota) (link para esta seção)
Template cujo cabeçalho é documento, imagem ou vídeo exige o anexo no envio. É o caso de entrega de pedido com o bilhete em PDF. Descubra quais dos seus templates precisam disso em Templates.
curl -X POST https://api.patrociniotech.com/public/v1/messages \
-H "Authorization: Bearer ptk_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "5521999999999",
"template": "entrega_pedido",
"language": "pt_BR",
"header_media": {
"type": "document",
"link": "https://sualoja.com.br/bilhetes/8421.pdf",
"filename": "Bilhete 8421.pdf"
},
"button_url_param": "8421",
"client_ref": "pedido-8421"
}'link precisa ser uma URL pública: quem baixa o arquivo é a Meta, e ela não faz login no seu sistema. Não é upload, o arquivo continua no seu servidor. Sem o anexo, o envio falha com 132012.O filename vale só para documento, e é o nome que a pessoa vê no WhatsApp. Guardamos ele junto da mensagem, então o atendente que abrir a conversa no painel vê qual bilhete foi enviado, e não só a palavra “template”.
Cobrança PIX (template de detalhes do pedido) (link para esta seção)
O cliente recebe um cartão com os itens e o total, e paga por PIX sem sair do WhatsApp. Só funciona em template criado no formato de cobrança (em Templates, campo Formato) e com pagamentos habilitados na sua conta da Meta.
49575. E a conta precisa fechar: a soma dos itens mais a taxa tem que dar o total, senão a chamada é recusada antes de sair daqui. Um valor errado no cartão de cobrança já é uma cobrança errada.curl -X POST https://api.patrociniotech.com/public/v1/messages \
-H "Authorization: Bearer ptk_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "5521999999999",
"template": "cobranca_emissao",
"language": "pt_BR",
"pix_order": {
"reference_id": "MP-PED-8421",
"pix_code": "00020101021226700014br.gov.bcb.pix...",
"merchant_name": "Sua Empresa LTDA",
"key": "39580525000189",
"key_type": "CNPJ",
"items": [
{ "name": "Emissao de passagem", "amount": 49575, "quantity": 1 }
],
"tax": 0
},
"client_ref": "pedido-8421"
}'O pix_code é o copia e cola que o seu PSP gerou para esta cobrança, e vai inteiro. O reference_id é o seu número do pedido: é por ele que você concilia o pagamento depois. key_type aceita CNPJ, CPF, EMAIL, PHONE e EVP (chave aleatória).
Campos do corpo (link para esta seção)
| Campo | Obrigatório | O que é |
|---|---|---|
| to | sim | Número do destinatário, só dígitos, com país e DDD. Ex.: 5521999999999. |
| text | um dos dois | Texto livre. Só funciona dentro da janela de 24h. Até 4096 caracteres. |
| template | um dos dois | Nome do template aprovado. Use fora da janela. |
| language | não | Idioma do template. Padrão pt_BR. |
| variables | não | Valores de {{1}} em diante, na ordem. Até 20. |
| variable_names | não | Nomes, quando o template usa variáveis nomeadas ({{pedido}}) em vez de numeradas. Mesmo tamanho de variables. |
| header_media | depende | Anexo do cabeçalho: {type, link, filename}. Obrigatório quando o template tem cabeçalho de documento, imagem ou vídeo. |
| header_text | depende | Valor da variável de um cabeçalho de TEXTO. Obrigatório quando o template tem uma. |
| button_url_param | depende | Trecho que a Meta anexa ao fim da URL de um botão dinâmico. Ex.: o id do pedido, ou o token de um link de acesso. |
| coupon_code | depende | Código que o cliente copia no botão de cupom (COPY_CODE). Obrigatório quando o template tem esse botão; muda por campanha. |
| coupon_index | não | Posição do botão de cupom na lista de botões do template. O padrão é 0. |
| button_url_index | não | Posição do botão de link na lista de botões do template, começando em 0. Só precisa mandar quando o template tem mais de um botão e o de link não é o primeiro (ex.: uma resposta rápida antes dele). O padrão é 0. |
| pix_order | depende | Cobrança PIX. Obrigatório quando o template é de cobrança. Valores em centavos, e a soma precisa fechar com o total. |
| reply_to_message_id | não | Responder citando uma mensagem. Use o message_id que veio em message.received. |
| phone_number_id | não | Número seu que dispara. Sem ele, usa o número padrão da conta. |
| client_ref | não | Seu identificador (id do pedido, do cliente, da linha da campanha). Volta em todo evento de status. |
client_ref: o campo mais útil daqui (link para esta seção)
Sem ele, para saber quem recebeu o quê você precisaria guardar uma tabela de-para entre o id do WhatsApp e o seu registro. Com ele, o seu próprio identificador volta em todo evento do webhook, e o de-para deixa de existir.
client_ref. Quando o status chegar, você marca aquela linha direto, sem consultar nada.Resposta (link para esta seção)
{
"success": true,
"data": {
"message_id": "wamid.HBgNNTUyMT...",
"status": "sent",
"to": "5521999999999",
"client_ref": "pedido-8421"
}
}Não enviar duas vezes (link para esta seção)
Mande o header Idempotency-Key com um valor único por mensagem (um uuid serve). Se a mesma chamada chegar de novo, devolvemos a resposta original em vez de enviar outra vez. Vale por pelo menos 24 horas.
Idempotency-Key: 6f1c2b7e-1f0a-4c3d-9a2b-5e8d1f0a4c3d
Isso existe por um motivo concreto: a resposta só volta depois que falamos com a Meta. Se a sua conexão cair nesse meio, o seu retry natural faria a pessoa receber duas vezes, e a conversa ser cobrada duas vezes. Com a chave, repetir é inofensivo. A resposta repetida vem com idempotent_replay: true.
A chave é reservada antes de falarmos com a Meta, e não depois. A diferença importa justamente no caso que ela existe para cobrir: a janela em que a sua conexão cai é a da chamada à Meta, então guardar só no fim deixaria o seu retry chegar antes de existir qualquer registro. São três respostas possíveis:
| Situação | O que você recebe | O que fazer |
|---|---|---|
| Chave nova | 200 com a mensagem enviada | Seguir. |
| Chave já concluída | 200 com a resposta original e idempotent_replay: true | Seguir: a mensagem saiu uma vez só. |
| Chave em andamento | 409 idempotency_in_flight | Esperar alguns segundos e repetir COM A MESMA CHAVE. É esta resposta que impede o envio duplo quando duas chamadas correm juntas. |
Validar o número antes (link para esta seção)
/public/v1/validateConfere o formato do número (DDI errado, tamanho errado, digitação) e devolve normalizado, pronto para usar no envio. Útil antes de importar uma lista grande.
curl -X POST https://api.patrociniotech.com/public/v1/validate \
-H "Authorization: Bearer ptk_live_..." \
-H "Content-Type: application/json" \
-d '{"to": "(21) 99999-9999", "country": "BR"}'