Responder
Envia ao cliente uma resposta em texto ou com imagem, vídeo, áudio e documento, e baixa as mídias que ele mandou.
Quando o atendente responde pelo painel, estas rotas fazem o envio pelo número de WhatsApp do seller. Para texto basta um corpo JSON. Para mídia, primeiro envie o arquivo com upload, que devolve uma URL, e então mande essa URL em reply-media: a Meta baixa o arquivo por esse link. A quarta rota baixa uma mídia que o cliente mandou.
Toda resposta é gravada na conversa antes de você saber se a Meta aceitou. Por isso uma falha de envio devolve 502 com a mensagem gravada, e não simplesmente um erro sem corpo útil.
Responder com texto
/api/v1/vendor/whatsapp/inbox/threads/{id}/replySellerEnvia uma mensagem de texto ao cliente
Envia o texto pelo número do seller (ou pelo número padrão da loja, se o seller não tem o seu). Não desliga o assistente automático da conversa.
Parâmetros de caminho
iduuidobrigatórioCorpo da requisição
bodystringobrigatórioreply_tostringwa_message_id, começa com wamid). A resposta aparece como citação no WhatsApp do cliente.Exemplo de requisição
curl -X POST "$BASE_URL/api/v1/vendor/whatsapp/inbox/threads/$THREAD_ID/reply" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"body": "Temos sim! Quer que eu separe o 42?"}'Resposta
{
"success": true,
"message": {
"id": 48213,
"phone_number": "5511999990000",
"message_type": "text",
"params": { "body": "Temos sim! Quer que eu separe o 42?" },
"status": "sent",
"whatsapp_message_id": "wamid.HBgNNTUxMTk5OTk5MDAwMBUCABEYEjQ1",
"sent_at": "2026-10-11T13:05:30Z",
"created_at": "2026-10-11T13:05:30Z"
}
}{
"error": "Cloud API send failed: whatsapp vendor inbox: send text: ...",
"message": {
"id": 48214,
"phone_number": "5511999990000",
"message_type": "text",
"params": { "body": "Temos sim! Quer que eu separe o 42?" },
"status": "sent",
"created_at": "2026-10-11T13:06:10Z"
}
}Campos da resposta
successbooleantrue quando a Meta aceitou a mensagem. Ausente no 502.messageobjectmessage.idintegermessage.phone_numberstringmessage.message_typestringtext nesta rota.message.paramsobject{"body": "..."} com o texto original que você enviou.message.statusstringsent mesmo no 502: confie no status HTTP, não nesse campo.message.whatsapp_message_idstringwamid...). Ausente quando o envio falhou.message.sent_atstringmessage.created_atstringErros
| Status | Quando | Corpo |
|---|---|---|
| 400 | JSON inválido | {"error":"invalid request body"} |
| 400 | body vazio | {"error":"body required"} |
| 401 / 403 | Sem token, token que não é de seller, módulo desligado, sem privilégio | veja Conversas |
| 404 | Conversa de outro seller ou inexistente | {"error":"thread not found"} |
| 502 | A Meta recusou (fora da janela de 24 horas, número sem credencial válida, etc.) | {"error":"Cloud API send failed: ...","message":{...}} |
| 500 | Falha ao gravar a mensagem | {"error":"Failed to send reply: ..."} |
Responder com mídia
/api/v1/vendor/whatsapp/inbox/threads/{id}/reply-mediaSellerEnvia imagem, vídeo, áudio ou documento ao cliente
A mídia precisa estar numa URL pública que a Meta consiga baixar. O fluxo normal é enviar o arquivo com upload e usar a url devolvida.
Parâmetros de caminho
iduuidobrigatórioCorpo da requisição
media_urlstringobrigatóriohttp ou https do arquivo, alcançável pela internet.media_typestringobrigatórioimagevideoaudiodocumentcaptionstringimage, video e document; em audio é ignorada.idempotency_keystringExemplo de requisição
curl -X POST "$BASE_URL/api/v1/vendor/whatsapp/inbox/threads/$THREAD_ID/reply-media" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"media_url": "https://minhaloja.io.venddor.com.br/uploads/tenis-preto.jpg",
"media_type": "image",
"caption": "Segue a foto do tênis preto",
"idempotency_key": "foto-tenis-9b1f"
}'Resposta
{
"success": true,
"message": {
"id": 48215,
"phone_number": "5511999990000",
"message_type": "image",
"status": "sent",
"whatsapp_message_id": "wamid.HBgNNTUxMTk5OTk5MDAwMBUCABEYEjQ2",
"created_at": "2026-10-11T13:07:02Z"
}
}Os campos de message são os mesmos da resposta de texto; aqui message_type repete o media_type enviado.
Erros
| Status | Quando | Corpo |
|---|---|---|
| 400 | JSON inválido | {"error":"invalid request body"} |
| 400 | media_url vazia | {"error":"media_url required"} |
| 400 | media_type fora dos quatro valores | {"error":"invalid media_type (image|video|audio|document)"} |
| 401 / 403 | Autenticação, módulo ou privilégio | veja Conversas |
| 404 | Conversa de outro seller ou inexistente | {"error":"thread not found"} |
| 502 | A Meta recusou o envio (por exemplo, não conseguiu baixar a URL) | {"error":"media send failed: ...","message":{...}} |
| 500 | Falha antes de gravar | {"error":"media send failed: ...","message":null} |
Enviar um arquivo
/api/v1/vendor/whatsapp/inbox/uploadSellerEnvia um arquivo e recebe a URL para usar em reply-media
Corpo multipart/form-data. É o mesmo enviador de mídia genérico da loja, aberto ao seller sem exigir o privilégio de mídia do administrador. O painel usa owner_type=whatsapp_thread e owner_id igual ao id da conversa.
Corpo da requisição
filefileobrigatórioowner_typestringobrigatóriowhatsapp_thread. Valores product e vendor só são aceitos para produtos e cadastro do próprio seller.owner_idstringobrigatóriowhatsapp_thread, o id da conversa.Exemplo de requisição
curl -X POST "$BASE_URL/api/v1/vendor/whatsapp/inbox/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@tenis-preto.jpg" \
-F "owner_type=whatsapp_thread" \
-F "owner_id=$THREAD_ID"Resposta
{
"id": "5d0c1a44-8f0e-4d6b-9a4e-0b8f7c1e2a33",
"tenant_id": "dfe2555e-bfd0-41a8-9fa1-9586999f3798",
"owner_id": "9b1f3c52-6a0e-4d57-8a43-2f6c1d7e90ab",
"owner_type": "whatsapp_thread",
"filename": "tenis-preto.jpg",
"content_type": "image/jpeg",
"size": 84213,
"url": "/uploads/dfe2555e/whatsapp_thread/tenis-preto.jpg",
"position": 0,
"created_at": "2026-10-11T13:06:40Z"
}Campos da resposta
iduuidurlstring/uploads/.... Em media_url use sempre a URL completa: se vier só o caminho, junte com $BASE_URL.filenamestringcontent_typestringsizeintegerowner_typestringowner_idstringpositionintegertenant_iduuidcreated_atstringErros
| Status | Quando | Corpo |
|---|---|---|
| 400 | Corpo que não é multipart ou grande demais | {"error":"failed to parse multipart form","detail":"..."} |
| 400 | Falta file, owner_type ou owner_id | {"error":"file is required"} / {"error":"owner_type is required"} / {"error":"owner_id is required"} |
| 400 | Tipo não aceito (inclui áudio MP3/OGG) | {"error":"unsupported file type","detail":"Allowed types: JPEG, PNG, GIF, WebP, AVIF, SVG, PDF, MP4. Detected: audio/mpeg"} |
| 403 | product ou vendor de outro seller | {"error":"owner_not_allowed","code":"owner_not_allowed"} |
| 500 | Falha ao gravar | {"error":"failed to upload file","detail":"..."} |
Baixar a mídia de uma mensagem
/api/v1/vendor/whatsapp/inbox/media/{message_id}SellerBaixa a imagem, o áudio ou o documento de uma mensagem
Devolve o arquivo da mensagem. Mídia recebida do cliente fica guardada na Meta (media_url começa com meta://); esta rota busca na Meta e guarda uma cópia para as próximas chamadas. Se a mensagem tem uma URL pública, a resposta é um redirecionamento 302 para ela.
Parâmetros de caminho
message_idintegerobrigatóriomessages[].id da conversa), não o id da Meta.Exemplo de requisição
curl -L "$BASE_URL/api/v1/vendor/whatsapp/inbox/media/48212" \
-H "Authorization: Bearer $TOKEN" -o foto.jpgResposta
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Disposition: inline; filename="foto.jpg"
Cache-Control: private, max-age=3600
(bytes do arquivo)O corpo é o arquivo em si, com o Content-Type da mídia. Em mídia com URL pública a resposta é 302 com Location apontando para ela.
Erros
| Status | Quando | Corpo |
|---|---|---|
| 400 | message_id não numérico ou menor que 1 | {"error":"invalid message_id"} |
| 400 | A mensagem não tem mídia | {"error":"message has no media"} |
| 404 | Mensagem de outro seller ou inexistente | {"error":"message not found"} |
| 502 | A Meta não entregou o arquivo (o link dela expira em minutos) | {"error":"media fetch failed: ..."} |
| 503 | A loja não tem token da Meta configurado | {"error":"whatsapp api token not configured"} |