Antonnia Docs
ConversationsGuides

Usando o Endpoint de Ingest

Como simplificar sua integração com o endpoint unificado de ingestão

O endpoint /ingest substitui o fluxo multi-chamada (criar sessão → enviar mensagem → disparar reply) por uma única chamada atômica. Ele é o ponto de entrada recomendado para qualquer integração de canal.

Antes vs. Depois

Antes (multi-chamada)

# 1. Lock distribuído (seu lado)
async with redis_lock(f"lock:{sender_id}"):
    # 2. Buscar sessão existente
    sessions = httpx.post(f"{BASE_URL}/sessions/search", headers=HEADERS, json={
        "contact_id": sender_id,
        "status": "open",
    }).json()

    if sessions:
        session = sessions[0]
    else:
        # 3. Criar sessão
        session = httpx.post(f"{BASE_URL}/sessions", headers=HEADERS, json={
            "contact_id": sender_id,
            "contact_name": sender_name,
            "agent_id": AGENT_ID,
        }).json()

    # 4. Enviar mensagem
    httpx.post(f"{BASE_URL}/sessions/{session['id']}/messages", headers=HEADERS, json={
        "content": {"type": "text", "text": message_text},
        "role": "user",
    })

    # 5. Disparar reply
    httpx.post(f"{BASE_URL}/sessions/{session['id']}/reply", headers=HEADERS, json={
        "debounce_time": 5,
    })

Depois (ingest)

# Uma única chamada — sem lock, sem busca de sessão
response = httpx.post(f"{BASE_URL}/ingest", headers=HEADERS, json={
    "to": channel_id,
    "from": sender_id,
    "channel_type": "whatsapp",
    "contact": {"name": sender_name, "phone": sender_phone},
    "content": {"type": "text", "text": message_text},
    "agent_id": AGENT_ID,
})

O ingest gerencia locks internamente via advisory locks no PostgreSQL. Você não precisa implementar locking distribuído.

Cenários comuns

Mensagem de texto simples

O caso mais frequente — encaminhar uma mensagem recebida do usuário:

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",
    "contact": { "name": "João" },
    "content": { "type": "text", "text": "Qual o status do meu pedido?" },
    "agent_id": "agent_suporte"
  }'
response = httpx.post(f"{BASE_URL}/ingest", headers=HEADERS, json={
    "to": "wn_55119999",
    "from": "+5511999888777",
    "contact": {"name": "João"},
    "content": {"type": "text", "text": "Qual o status do meu pedido?"},
    "agent_id": "agent_suporte",
})

Mídia (imagem, áudio, vídeo)

Envie o campo content com o tipo apropriado:

{
  "to": "wn_55119999",
  "from": "+5511999888777",
  "content": {
    "type": "image",
    "url": "https://cdn.example.com/photo.jpg"
  }
}

Tipos suportados: text, image, audio, video, file.

Transferir sessão para outro agente

Altere o agente sem enviar mensagem:

{
  "to": "wn_55119999",
  "from": "+5511999888777",
  "agent_id": "agent_humano_01"
}

Se o agente anterior era ai e o novo é human, a IA para de responder automaticamente.

Fechar sessão após última mensagem

Use session: "close" para inserir a mensagem e fechar na mesma chamada:

{
  "to": "wn_55119999",
  "from": "+5511999888777",
  "content": { "type": "text", "text": "Obrigado, resolvido!" },
  "session": "close"
}

Forçar nova sessão

Quando o contexto muda e é necessário reiniciar (ex.: novo atendimento):

{
  "to": "wn_55119999",
  "from": "+5511999888777",
  "content": { "type": "text", "text": "Preciso de ajuda com outro assunto" },
  "session": "new",
  "agent_id": "agent_suporte"
}

Isso fecha a sessão atual e cria uma nova, garantindo que a IA tenha contexto limpo.

Metadata da sessão (merge patch)

Atualize metadados da sessão de forma incremental:

{
  "to": "wn_55119999",
  "from": "+5511999888777",
  "metadata": {
    "priority": "urgent",
    "department": "billing",
    "old_field": null
  }
}
  • priority e department são adicionados/atualizados
  • old_field é removido (valor null remove a chave)
  • Campos existentes não mencionados permanecem inalterados

Integração completa (exemplo)

from fastapi import FastAPI, Request
import httpx

app = FastAPI()

BASE_URL = "https://services.antonnia.com/conversations/v2/api/v1"
HEADERS = {"Authorization": "Bearer sk_live_YOUR_TOKEN"}
AGENT_ID = "agent_suporte"
http_client = httpx.AsyncClient()

@app.post("/webhook/incoming")
async def handle_incoming(request: Request):
    event = await request.json()

    # Inbound: canal → Antonnia (uma chamada faz tudo)
    response = await http_client.post(f"{BASE_URL}/ingest", headers=HEADERS, json={
        "to": event["channel_id"],
        "from": event["sender_id"],
        "channel_type": "whatsapp",
        "contact": {
            "name": event.get("sender_name"),
            "phone": event["sender_id"],
        },
        "content": {"type": "text", "text": event["text"]},
        "role": "user",
        "provider_message_id": event["message_id"],
        "agent_id": AGENT_ID,
    })

    result = response.json()
    return {"status": "ok", "session_id": result["session_id"]}


@app.post("/webhook/antonnia")
async def handle_outbound(request: Request):
    event = await request.json()

    if event["type"] == "message.created":
        message = event["data"]["object"]
        if message["role"] == "assistant" and message["content"]["type"] == "text":
            # Entregar via seu canal
            await deliver_to_channel(message)

Quando usar ingest vs. APIs individuais

Use ingest quando...Use APIs individuais quando...
Recebendo mensagens de um canalBuscando histórico de sessões
Criando sessão + mensagem atomicamenteAtualizando status de entrega de mensagem
Transferindo agenteListando agentes disponíveis
Fechando sessãoBuscando dados de sessão por filtros

Próximos passos

On this page