Mensagens
O ciclo de vida de uma mensagem, do envio ao recibo — e o que é `null`.
Uma mensagem pertence a uma conversa e tem uma direção: inbound quando veio do contato, outbound quando saiu de você.
Enviar
Uma rota, todos os canais. A conversa determina por onde a mensagem sai — e as capacidades do canal são conferidas antes de qualquer coisa ser gravada.
curl https://api.amivu.com.br/v1/messages \
-H "Authorization: Bearer $AMIVU_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-8291-entrega" \
-d '{
"conversation_id": "conv_01K7ZFA5X8Q2M4N6P8R0T2V4W6",
"type": "text",
"text": "Seu pedido saiu para entrega."
}'
Imagem, vídeo, áudio e documento
Mídia são duas chamadas: suba o arquivo em POST /v1/uploads e envie o attachment_id que voltou, com o type do arquivo e, se quiser, uma legenda em text. O envio é o mesmo que o atendente faz pelo painel — mesma fila, mesmos recibos. Tipos aceitos, limite de tamanho e validade do anexo estão em Anexos e mídia.
curl https://api.amivu.com.br/v1/messages \
-H "Authorization: Bearer $AMIVU_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-8291-catalogo" \
-d '{
"conversation_id": "conv_01K7ZFA5X8Q2M4N6P8R0T2V4W6",
"type": "document",
"attachment_id": "att_01K7ZFA5X8Q2M4N6P8R0T2V4W6",
"text": "Segue o catálogo."
}'
type: "template" faz parte do schema, mas é recusado com 422 unsupported_message_type em qualquer canal. Não é falha passageira: retentar não adianta. Quando isso mudar, entra no changelog.422 unsupported_message_type e a conversa fica intacta. Gravar primeiro e descobrir depois deixaria um balão na tela do atendente que o cliente nunca recebeu.O ciclo de vida
queued ──▶ sent ──▶ delivered ──▶ read
│ │
└─────────┴──▶ failed
queued— aceita por nós. Ainda não entregue ao canal.sent— o canal aceitou a mensagem.delivered— o canal confirmou que chegou ao aparelho.read— o contato leu.failed— o canal recusou. O motivo vem emerror.
A resposta de POST /v1/messages devolve queued, e isso é deliberado: o retorno síncrono do provedor confirma apenas o enfileiramento na ponta dele. A falha real chega depois, por webhook de status. Tratar o 201 como “entregue” é o erro de integração mais comum com qualquer API de mensageria.
Quando status é null
Duas situações, e as duas são informação:
- Mensagem recebida — quem entregou foi o outro lado; não há estado nosso a reportar.
- Canal sem recibo — a conversa não passa por um transporte que confirme entrega. É o caso do registro manual.
A Amivu não fabrica estado. Preencher delivered porque “provavelmente chegou” seria mentir num campo em que integrações tomam decisões — inclusive a de cobrar alguém.
Para saber o que um canal específico reporta, leia capabilities.delivery_receipts e capabilities.read_receipts em GET /v1/channels/{id}.
Quando falha
{
"object": "message",
"id": "msg_01K7ZFA5X8Q2M4N6P8R0T2V4W6",
"status": "failed",
"error": {
"code": "130497",
"message": "Conta sem verificação de negócio para enviar a este destino."
}
}
O code é o do provedor, repassado sem tradução. Ele pede ação humana com muito mais frequência do que uma retentativa resolveria — e é por isso que a Amivu não reenvia sozinha: um número bloqueado continua bloqueado na décima tentativa.
Receber
Não pergunte de tempos em tempos. Assine message.received e a Amivu faz um POST assinado no seu endpoint com a mensagem e a conversa dentro.
Mensagem com mídia traz o arquivo em attachment.url, baixável com a mesma chave — ver Anexos e mídia.
Se precisar mesmo ler o histórico — para montar uma tela, por exemplo — GET /v1/conversations/{id}/messages devolve da mais nova para a mais velha, com cursor.
Escrevemos sobre operação de atendimento, canais e IA no blog da Amivu.