ConversationsApi reference
API de Ingest
Referência completa do endpoint unificado de ingestão de mensagens
Ingest
Endpoint unificado que, em uma única chamada, lida com:
- Busca ou criação de conversa
- Ciclo de vida da sessão (continuar, criar nova, fechar)
- Envio de mensagem
- Transferência de agente
- Disparo automático de resposta da IA
POST /ingestCorpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
to | string | Sim | ID do canal (ex.: "wn_55119999") |
from | string | Sim | ID do usuário no canal (ex.: "+5511999999999") |
channel_type | string | Não | Tipo do canal. Padrão: "whatsapp" |
contact | object | Não | Dados do contato (ver abaixo) |
content | object | Não | Corpo da mensagem (ver abaixo). Omita para operações sem mensagem |
role | string | Não | "user" (padrão) ou "assistant" |
provider_message_id | string | Não | ID da mensagem no provedor externo |
session | string | Não | "continue" (padrão), "new" ou "close" |
agent_id | string | Não | ID do agente. Omita para manter o atual; envie null para desassociar |
metadata | object | Não | RFC 7396 merge patch no metadata da sessão |
Objeto contact
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Condicional | Nome do contato |
phone | string | Condicional | Telefone do contato |
Ao menos um campo (name ou phone) deve ser fornecido se o objeto contact estiver presente. Omita contact inteiramente quando não houver informação adicional — o from já identifica o usuário.
Objeto content
O campo content aceita um dos seguintes tipos:
| Tipo | Campos | Descrição |
|---|---|---|
text | type, text | Mensagem de texto |
image | type, url | Imagem (URL) |
audio | type, url, transcript? | Áudio (URL + transcrição opcional) |
video | type, url | Vídeo (URL) |
file | type, url, mime_type, name | Arquivo genérico |
Semântica do campo session
| Valor | Comportamento |
|---|---|
"continue" | Reutiliza sessão aberta existente ou cria uma nova caso não exista |
"new" | Fecha a sessão aberta atual e cria uma nova |
"close" | Insere a mensagem (se houver) e então fecha a sessão |
Semântica do campo metadata
O metadata usa RFC 7396 (JSON Merge Patch) recursivo:
- Valores
nulldentro do objeto removem as chaves - Objetos aninhados são mesclados recursivamente (não substituição rasa)
- Omitir o campo inteiramente não altera o metadata existente
Exemplo de requisição
curl -X POST https://services.antonnia.com/conversations/v2/api/v1/ingest \
-H "Authorization: Bearer sk_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "wn_55119999",
"from": "+5511999888777",
"channel_type": "whatsapp",
"contact": {
"name": "Maria Silva",
"phone": "+5511999888777"
},
"content": {
"type": "text",
"text": "Olá, preciso de ajuda com meu pedido"
},
"role": "user",
"session": "continue",
"agent_id": "agent_abc",
"metadata": {
"source": "whatsapp",
"priority": "high"
}
}'import httpx
BASE_URL = "https://services.antonnia.com/conversations/v2/api/v1"
HEADERS = {
"Authorization": "Bearer sk_live_YOUR_TOKEN",
"Content-Type": "application/json",
}
response = httpx.post(f"{BASE_URL}/ingest", headers=HEADERS, json={
"to": "wn_55119999",
"from": "+5511999888777",
"channel_type": "whatsapp",
"contact": {
"name": "Maria Silva",
"phone": "+5511999888777",
},
"content": {
"type": "text",
"text": "Olá, preciso de ajuda com meu pedido",
},
"role": "user",
"session": "continue",
"agent_id": "agent_abc",
"metadata": {
"source": "whatsapp",
"priority": "high",
},
})
result = response.json()Response 200
{
"conversation_id": "conv_abc123",
"session_id": "sess_xyz789",
"message_id": "msg_def456",
"created_conversation": false,
"created_session": true
}| Campo | Tipo | Descrição |
|---|---|---|
conversation_id | string | ID da conversa (criada ou reutilizada) |
session_id | string | null | ID da sessão (null se não houver contexto de sessão) |
message_id | string | null | ID da mensagem (null se content não foi enviado) |
created_conversation | boolean | true se a conversa foi criada nesta chamada |
created_session | boolean | true se a sessão foi criada nesta chamada |
Erros
| Status | Detalhe | Causa |
|---|---|---|
| 401 | Unauthorized | Token inválido ou ausente |
| 502 | Ingest RPC returned no data | O banco não retornou dados |
| 502 | Ingest RPC returned unexpected shape | Estrutura de retorno inesperada |
| 500 | Internal server error | Erro interno não tratado |
Comportamentos automáticos
- Criação de contato: Se o contato não existir, ele é criado automaticamente com os dados fornecidos
- Criação de conversa: Se não existir conversa para o par (canal + usuário), uma nova é criada
- Resposta da IA: Se a sessão tem um agente do tipo
aie uma mensagem foi criada, a resposta da IA é disparada automaticamente com debounce configurável - Eventos: Cada transição de estado gera eventos internos (conversation.created, session.created, session.transferred, session.closed, message.created)
Operações sem mensagem
O endpoint aceita chamadas sem content para operações de controle:
{
"to": "wn_55119999",
"from": "+5511999888777",
"agent_id": "agent_new"
}{
"to": "wn_55119999",
"from": "+5511999888777",
"session": "close"
}{
"to": "wn_55119999",
"from": "+5511999888777",
"metadata": { "priority": "urgent", "old_key": null }
}Concorrência
O endpoint usa advisory locks no PostgreSQL para serializar operações concorrentes no mesmo par (canal + usuário), garantindo que mensagens simultâneas não criem sessões ou conversas duplicadas. Não é necessário implementar locking distribuído do lado do cliente.