Envio de mensagens multi-canal na Plataforma Keeptor via blocos de conteudo normalizados.
Mensagens
Endpoints para enviar mensagens nos canais conectados da Plataforma Keeptor. V1 cobre WhatsApp. A arquitetura foi desenhada para incluir Email, Instagram e Telegram no futuro sem mudar essa API: o conteúdo é descrito de forma agnóstica ao canal e a Plataforma adapta o envio automaticamente.
Autenticação
Todas as rotas exigem Authorization: Bearer <access_token> (obtido via Login). Você só envia mensagens em conversas da sua própria organização.
Convenção de URL
Todas as URLs são prefixadas por:
- Produção:
https://api.keeptor.com/prd/v1/omni/messages - Homologação:
https://api.keeptor.com/tst/v1/omni/messages
Estrutura de conteúdo: content_blocks
content_blocksToda mensagem é composta por um array de blocos de conteúdo (content_blocks). Cada bloco tem um campo type que define seu formato. Esse modelo permite descrever qualquer mensagem, de um texto simples a um carrossel interativo, com um único contrato, independente do canal de destino.
Exemplos de composição:
- Um WhatsApp com texto + foto →
[ {type:"text"}, {type:"image"} ] - Um carrossel → um único bloco
{type:"carousel"}com os cards emitems - Uma resposta citando outra mensagem → o campo
reply_to_message_idno envio
A Plataforma identifica o canal pela conversa informada (conversation_id) e adapta o envio. Você não precisa saber se a conversa é WhatsApp, Email ou outro canal: basta montar os blocos.
Catálogo de tipos de bloco
São 20 tipos de bloco. Nem todo canal suporta todos os tipos; a Plataforma valida a compatibilidade no momento do envio.
type | Descrição | Universal | Interativo | Sistema | |
|---|---|---|---|---|---|
text | Texto puro | sim | |||
image | Imagem com legenda opcional | sim | |||
audio | Áudio (voz ou arquivo) | sim | |||
video | Vídeo com legenda opcional | sim | |||
document | Documento ou anexo | sim | |||
sticker | Figurinha | sim | |||
location | Localização geográfica | sim | |||
contact | Cartão de contato (vCard) | sim | |||
button | Mensagem com até 3 botões interativos | sim | |||
list | Lista interativa (menu de opções) | sim | |||
template | Modelo pré-aprovado com variáveis dinâmicas | sim | |||
carousel | Carrossel de cards (mensagem única) | sim | |||
email_html | E-mail com corpo HTML rico | sim | |||
email_plain | E-mail em texto puro | sim | |||
reaction | Reação (emoji) a uma mensagem | sim | |||
reply | Resposta encadeada (quote) | sim | |||
forward | Encaminhamento de uma mensagem | sim | |||
note | Nota interna (não enviada ao contato) | sim | |||
deleted | Placeholder de mensagem excluída | sim | |||
unknown | Conteúdo bruto preservado para auditoria | sim |
Capability matrix: a combinação de canal × tipo de bloco suportada é mantida pela Plataforma e exposta via
/v1/dictionary. O cliente pode consultar quais tipos cada canal aceita antes de montar a mensagem.
Estados da mensagem (status_code)
status_code)status_code | Significado |
|---|---|
queued | Mensagem aceita e aguardando envio |
sent | Mensagem entregue ao canal |
delivered | Mensagem entregue ao destinatário |
read | Mensagem lida pelo destinatário |
failed | Falha no envio |
Uma resposta 200 no envio significa apenas que a mensagem foi aceita e enfileirada (queued). A evolução do status (sent, delivered, read) chega de forma assíncrona.
Erros
Toda resposta de erro segue o schema ErrorResponse. Mostre ao usuário o message; para reconhecer o erro no seu código, use error.key, que não muda com o idioma nem com o texto. error.code está sempre presente; error.field aponta o campo que causou o erro (para exibir a mensagem embaixo dele); error.internal descreve a regra para o suporte. Exemplo real:
{
"success": false,
"message": "Conversa não encontrada.",
"error": {
"type": "NOT_FOUND",
"code": "NOT_FOUND",
"message": "Conversa não encontrada.",
"key": "gateway.omni.messages.conversation_not_found",
"params": {},
"field": "conversation_id",
"internal": "A conversa não existe ou não é da organização da sessão. Responde 404.",
"fields": ["conversation_id"]
}
}| HTTP | error.key | Quando |
|---|---|---|
| 400 / 422 | gateway.omni.messages.payload_invalid | Corpo fora do formato aceito; o motivo técnico vem em error.details.reason (não exiba ao usuário) |
| 400 | gateway.omni.messages.channel_unsupported | Tipo de canal sem envio |
| 401 | gateway.auth.token_missing / gateway.auth.session_expired | Sem token, ou sessão expirada |
| 404 | gateway.omni.messages.conversation_not_found | Conversa inexistente ou de outra organização |
| 404 | gateway.omni.messages.channel_not_found | A conversa aponta para um canal que não existe mais |
| 404 | gateway.omni.messages.poll_not_found | Voto em enquete que não existe na conversa |
| 501 | gateway.omni.messages.email_unavailable | Envio por e-mail ainda não disponível |
| 503 | gateway.omni.messages.send_failed | O canal recusou ou não respondeu ao envio. Tente de novo |
| 503 | gateway.omni.channel_provider_missing | Cadastro de provedores fora do ar |
| 500 | gateway.omni.operation_failed | Falha interna sem mensagem própria |
Eventos em tempo real
Quando uma mensagem é enviada e quando seu status evolui, a Plataforma emite eventos em tempo real. O cliente assina o canal da conversa para receber as atualizações sem fazer polling.