Programa com IA? Conecte-a à sua conta por MCP: ela revisa sua configuração, cria webhooks e modelos com sua confirmação e escreve o código. Veja como →
Uma mensagem com 2 a 10 cartões que deslizam, cada um com sua foto ou vídeo, seu texto e seus botões. Você monta pelo seu sistema e envia para aprovação, como qualquer modelo:
1. Uma amostra por cartão:POST /v1/templates/media com a imagem (JPG/PNG) ou o vídeo (MP4) → handle. É o que a Meta revisa; em cada envio vai a foto de verdade. 2. Criar:POST /v1/templates com category: "MARKETING", o body principal e carousel.cards[]. Cada cartão: header { format: IMAGE|VIDEO, handle }, body opcional e até 2 botões (QUICK_REPLY, URL, PHONE_NUMBER). Antes da Meta checamos as regras dela: a mesma quantidade de cartões ao enviar, o mesmo formato em todos, os mesmos botões na mesma ordem, o texto do cartão até 160 caracteres (em todos ou em nenhum) e exemplos para cada {{n}}. POST /v1/templates/validate testa sem criar nada; /preview?format=html desenha a faixa deslizante. 3. Esperartemplate.status_changed com APPROVED. 4. Enviar:POST /v1/messages com template.carousel.cards[], um por cartão e em ordem: o header (image/video com mediaId ou link), os valores do body e dos botões (quick_reply → seu payload, url → o final do link). 5. O toque: chega message.received com button.payload intacto e tap { cardIndex, buttonIndex }. A Meta não manda esses índices: nós os resolvemos com o seu payload.
O que a Meta define: o carrossel existe só como MARKETING e cada envio é cobrado como marketing; a Meta aprova ou rejeita como qualquer modelo; desde 1/4/2025 não entrega marketing a números dos EUA (131049), e aplica seus limites por pessoa a todo o marketing.
# 1) One sample image per card (Meta reviews them) → handles
H1=$(curl -s -X POST https://api.waiaconnect.com/v1/templates/media -H "Authorization: Bearer wc_live_YOUR_API_KEY" -F file=@remera.jpg | jq -r .handle)
H2=$(curl -s -X POST https://api.waiaconnect.com/v1/templates/media -H "Authorization: Bearer wc_live_YOUR_API_KEY" -F file=@buzo.jpg | jq -r .handle)
# 2) Create the carousel (MARKETING, 2–10 cards, same buttons in every card)
BODY='{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","name":"novedades_semana","language":"es","category":"MARKETING","body":{"text":"Hola {{1}}, mirá lo nuevo de esta semana.","examples":["Martín"]},"carousel":{"cards":[{"header":{"format":"IMAGE","handle":"H1"},"body":{"text":"Remera {{1}} de algodón.","examples":["azul"]},"buttons":[{"type":"QUICK_REPLY","text":"Me interesa"},{"type":"URL","text":"Ver","url":"https://your-shop.example/p/{{1}}","example":"remera-azul"}]},{"header":{"format":"IMAGE","handle":"H2"},"body":{"text":"Buzo {{1}} de algodón.","examples":["gris"]},"buttons":[{"type":"QUICK_REPLY","text":"Me interesa"},{"type":"URL","text":"Ver","url":"https://your-shop.example/p/{{1}}","example":"buzo-gris"}]}]}}'
BODY=${BODY/H1/$H1}; BODY=${BODY/H2/$H2}
curl -s -X POST https://api.waiaconnect.com/v1/templates/validate -H "Authorization: Bearer wc_live_YOUR_API_KEY" -H "Content-Type: application/json" -d "$BODY"
curl -s -X POST https://api.waiaconnect.com/v1/templates -H "Authorization: Bearer wc_live_YOUR_API_KEY" -H "Content-Type: application/json" -d "$BODY"
# 3) Wait for the template.status_changed webhook with status APPROVED
# 4) Send it: one card per card of the template, in order
curl -s -X POST https://api.waiaconnect.com/v1/messages -H "Authorization: Bearer wc_live_YOUR_API_KEY" \
-H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" \
-d '{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"template","template":{"name":"novedades_semana","language":"es","body":["Sofía"],"carousel":{"cards":[{"header":{"type":"image","link":"https://your-shop.example/img/remera-azul.jpg"},"body":["azul"],"buttons":[{"type":"quick_reply","payload":"remera-azul:me-interesa"},{"type":"url","text":"remera-azul"}]},{"header":{"type":"image","link":"https://your-shop.example/img/buzo-gris.jpg"},"body":["gris"],"buttons":[{"type":"quick_reply","payload":"buzo-gris:me-interesa"},{"type":"url","text":"buzo-gris"}]}]}}}'
# 5) The tap arrives as message.received:
# data.message.button.payload = "buzo-gris:me-interesa" (yours, intact)
# data.tap = { "cardIndex": 1, "buttonIndex": 0 }
import uuid, requests
H = {"Authorization": "Bearer wc_live_YOUR_API_KEY"}
# 1) One sample image per card (Meta reviews them) -> handles
h1 = requests.post("https://api.waiaconnect.com/v1/templates/media", headers=H, files={"file": open("remera.jpg", "rb")}).json()["handle"]
h2 = requests.post("https://api.waiaconnect.com/v1/templates/media", headers=H, files={"file": open("buzo.jpg", "rb")}).json()["handle"]
# 2) Create the carousel (MARKETING, 2-10 cards, same buttons in every card)
definition = {"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","name":"novedades_semana","language":"es","category":"MARKETING","body":{"text":"Hola {{1}}, mirá lo nuevo de esta semana.","examples":["Martín"]},"carousel":{"cards":[{"header":{"format":"IMAGE","handle":h1},"body":{"text":"Remera {{1}} de algodón.","examples":["azul"]},"buttons":[{"type":"QUICK_REPLY","text":"Me interesa"},{"type":"URL","text":"Ver","url":"https://your-shop.example/p/{{1}}","example":"remera-azul"}]},{"header":{"format":"IMAGE","handle":h2},"body":{"text":"Buzo {{1}} de algodón.","examples":["gris"]},"buttons":[{"type":"QUICK_REPLY","text":"Me interesa"},{"type":"URL","text":"Ver","url":"https://your-shop.example/p/{{1}}","example":"buzo-gris"}]}]}}
requests.post("https://api.waiaconnect.com/v1/templates", headers=H, json=definition).raise_for_status()
# 3) Wait for template.status_changed (APPROVED) on your webhook, then
# 4) send it: one card per card of the template, in order
requests.post("https://api.waiaconnect.com/v1/messages", headers={**H, "Idempotency-Key": str(uuid.uuid4())}, json={"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"template","template":{"name":"novedades_semana","language":"es","body":["Sofía"],"carousel":{"cards":[{"header":{"type":"image","link":"https://your-shop.example/img/remera-azul.jpg"},"body":["azul"],"buttons":[{"type":"quick_reply","payload":"remera-azul:me-interesa"},{"type":"url","text":"remera-azul"}]},{"header":{"type":"image","link":"https://your-shop.example/img/buzo-gris.jpg"},"body":["gris"],"buttons":[{"type":"quick_reply","payload":"buzo-gris:me-interesa"},{"type":"url","text":"buzo-gris"}]}]}}})
# 5) In your webhook handler: which card and which button
def on_event(evt):
if evt["type"] == "message.received" and evt["data"]["message"]["type"] == "button":
payload = evt["data"]["message"]["button"]["payload"] # yours, intact
tap = evt["data"].get("tap") # {"cardIndex": 1, "buttonIndex": 0}
print(payload, tap)
Dê a cada resposta rápida o seu próprio payload (por exemplo moletom-cinza:quero): com dois iguais na mesma mensagem não dá para saber qual foi tocado, e tap não vem. Um «Sair da lista» como resposta rápida chega igual: o descadastro fica com o seu sistema.
Os botões de link e de ligação não geram aviso: a Meta abre o navegador ou o telefone.
Um carrossel criado no WhatsApp Manager é sincronizado com seus cartões (GET /v1/templates, carousel.cards) e é enviado igual.
O carrossel de produtos do catálogo (botão «Ver», compra dentro do WhatsApp) ainda não.