# Atalia API de integração (v1) > API para enviar e receber mensagens de WhatsApp, Instagram e Messenger pelos canais conectados na Atalia. O seu sistema envia pela API e recebe cada mensagem dos clientes no seu webhook. Base: https://chat.atalia.com.br/api/v1. Todo corpo é JSON (UTF-8). Este arquivo é a referência completa da API v1, escrita para ser lida por assistentes de IA e por pessoas. Se algo aqui contradiz outra página, vale este arquivo. Guia para pessoas: https://chat.atalia.com.br/docs/integracao/visao-geral. Referência navegável (seção Integração): https://chat.atalia.com.br/docs/api/atalia-api ## Autenticação - Envie a chave da empresa no header `x-api-key: atk_live_...` (ou `Authorization: Bearer atk_live_...`). - A chave é gerada no painel da Atalia, em "Chave e webhook" (ou Configurações › Integração via API). Ela aparece inteira uma vez só; gerar uma nova revoga a anterior na hora. - A chave só abre `/api/v1/*`. Use apenas no servidor, nunca em código que roda no navegador ou no app. - A empresa vem da chave: não envie `X-Company-Id` (ele é do token pessoal). - Não confunda com o **token pessoal** do Perfil: ele age em nome de um usuário, abre as outras rotas `/api/...` (conversas, contatos, agentes) e NÃO abre `/api/v1`. Para integrar um sistema, use a chave da empresa. - Sem chave: `401 MISSING_API_KEY`. Chave errada ou revogada: `401 INVALID_API_KEY`. Token pessoal no lugar da chave: `401 PERSONAL_TOKEN_NOT_ALLOWED`. ## Formato de erro Todo erro devolve status HTTP 4xx/5xx e o corpo: ```json { "error": { "code": "CHANNEL_NOT_FOUND", "message": "Canal não encontrado." } } ``` Códigos: `MISSING_API_KEY`, `INVALID_API_KEY`, `PERSONAL_TOKEN_NOT_ALLOWED`, `INVALID_JSON`, `CHANNEL_REQUIRED`, `CHANNEL_NOT_FOUND`, `CHANNEL_NOT_SUPPORTED`, `CHANNEL_NOT_READY`, `RECIPIENT_REQUIRED`, `INVALID_PHONE`, `CONVERSATION_NOT_FOUND`, `CONVERSATION_REQUIRED`, `TEMPLATES_NOT_SUPPORTED`, `TEMPLATE_REQUIRED`, `WINDOW_CLOSED`, `SEND_REJECTED`, `INVALID_MESSAGE`, `MESSAGE_NOT_FOUND`, `MEDIA_NOT_FOUND`, `MEDIA_PROCESSING`, `WEBHOOK_NOT_CONFIGURED`, `RESELLER_ONLY`, `CONNECT_PAGE_REQUIRED`, `CLIENT_NOT_FOUND`, `INVALID_CLIENT`. ## IDs - Canal: `ch_` + hexadecimal (ex.: `ch_2f81a9c0d1`). Aparece na tela "Canais" do painel e em `GET /channels`. - Mensagem: UUID (ex.: `6f1c2a7e-0b8e-4d0a-9a51-3f7c1e2d9b10`). - Conversa: texto numérico (ex.: `"48213"`). Chega nos eventos `message.received`; use para responder. - `client_id`: só para revendedores. Identifica o cliente (empresa filha) dono do canal; `null` quando o canal é seu. ## Canais ### GET /channels Lista os canais que a chave pode usar (os seus e, para revendedores, os dos seus clientes). ```json { "data": [ { "id": "ch_2f81a9c0d1", "type": "whatsapp", "name": "Atendimento", "status": "active", "phone": "+55 11 98765-4321", "client_id": null, "created_at": "2026-10-20 10:00:00" } ] } ``` `type`: `whatsapp` (oficial, inclusive coexistência com o app WhatsApp Business), `whatsapp_web`, `instagram` (traz `username`) ou `messenger` (traz `page_name`). ### GET /channels/{channel_id}/templates Templates do WhatsApp oficial cadastrados no canal: `name`, `language`, `category`, `status` (`APPROVED`, `PENDING`, `REJECTED`) e `components` no formato da Meta. ### DELETE /channels/{channel_id} Apaga o canal (seu ou de um cliente da revenda) com o histórico. O número (ou a conta do Instagram/Messenger) deixa de estar ligado à Atalia na Meta e pode ser conectado em outro lugar. Responde `{ "data": { "id": "ch_...", "deleted": true } }` e o webhook recebe `channel.disconnected`. Não dá para desfazer: para usar de novo, conecte outra vez. ### POST /channels/{channel_id}/templates/sync Busca de novo na Meta os templates do canal (use depois de criar ou editar um template no Gerenciador do WhatsApp). ## Enviar mensagem ### POST /messages Destinatário, um dos dois: - `to`: telefone em formato internacional (`+5511987654321`). Só WhatsApp. Cria o contato e a conversa se ainda não existirem. `contact_name` é opcional. - `conversation_id`: a conversa recebida no evento `message.received`. Obrigatório no Instagram e no Messenger. Responde `202` com a mensagem aceita na fila. O resultado da entrega chega depois pelo evento `message.status`. ```json { "data": { "id": "6f1c2a7e-0b8e-4d0a-9a51-3f7c1e2d9b10", "status": "pending", "conversation_id": "48213", "created_at": "2026-10-28 14:02:11" } } ``` Header opcional `Idempotency-Key: `: repetir a mesma chave em até 24 h devolve a mesma resposta sem enviar de novo. Use em toda retentativa. Exemplos de corpo: ```json { "channel_id": "ch_2f81a9c0d1", "to": "+5511987654321", "type": "text", "text": "Olá! Seu pedido saiu para entrega." } ``` ```json { "channel_id": "ch_2f81a9c0d1", "conversation_id": "48213", "type": "text", "text": "Obrigado pelo contato!" } ``` Template (WhatsApp oficial; obrigatório para começar conversa ou falar depois de 24 h sem mensagem do cliente). `components` no formato de ENVIO da Meta, com `parameters`: ```json { "channel_id": "ch_2f81a9c0d1", "to": "+5511987654321", "type": "template", "template": { "name": "pedido_enviado", "language": "pt_BR", "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Ana" }, { "type": "text", "text": "#1042" } ] } ] } } ``` Mídia (`image`, `video`, `audio`, `document`). A `url` tem que ser https e pública; a Atalia baixa e envia: ```json { "channel_id": "ch_2f81a9c0d1", "conversation_id": "48213", "type": "document", "url": "https://exemplo.com/nota-1042.pdf", "filename": "nota-1042.pdf", "caption": "Sua nota fiscal" } ``` Botões de resposta (até 3, título até 20 caracteres): ```json { "channel_id": "ch_2f81a9c0d1", "conversation_id": "48213", "type": "buttons", "body": "Confirma o horário de amanhã às 14h?", "buttons": [ { "id": "confirmar", "title": "Confirmar" }, { "id": "remarcar", "title": "Remarcar" } ] } ``` Outros tipos: `list` (`body`, `button`, `sections`), `cta_url` (`body`, `display_text`, `url`), `carousel` (`body_text`, `cards`), `location` (`latitude`, `longitude`, `name`, `address`) e `contacts` (`contacts`). Fora do WhatsApp oficial, o que o canal não suporta é adaptado ou vira texto automaticamente. Janela de atendimento: - WhatsApp oficial: texto, mídia e interativos só dentro de 24 h da última mensagem do cliente. Fora dela, ou antes de o cliente escrever, envie um template (`403 TEMPLATE_REQUIRED`). O template precisa estar `APPROVED` no canal. - Instagram e Messenger: só é possível responder quem escreveu antes, dentro da janela da Meta (`403 WINDOW_CLOSED`). ### GET /messages/{message_id} Mensagem e status atual (`pending`, `sent`, `delivered`, `read`, `failed`). Em `failed`, `error` traz o motivo. ```json { "data": { "id": "6f1c...", "external_id": "wamid.HBgN...", "direction": "outbound", "type": "text", "text": "Olá!", "media": null, "status": "delivered", "channel_id": "ch_2f81a9c0d1", "conversation_id": "48213", "error": null, "created_at": "2026-10-28 14:02:11" } } ``` ### GET /media/{message_id} Baixa a mídia de uma mensagem (foto, áudio, documento recebido). Responde `302` para um link assinado válido por 5 minutos; siga o redirecionamento. `409 MEDIA_PROCESSING` = a mídia ainda está sendo baixada, tente de novo em alguns segundos. ## Webhook (receber mensagens) Cadastre um endereço https público no painel ("Chave e webhook"). A Atalia faz um `POST` JSON para ele a cada evento. - Responda `2xx` em até 10 segundos. Grave o evento e processe depois. Qualquer outra resposta (ou demora) é falha. - Falha = nova tentativa, até 9 tentativas no total, esperando 30 s, 1 min, 2 min, 4 min, 8 min, 16 min, 32 min e 1 h (cerca de 2 h). Depois disso o evento fica como "Falhou" no painel (Entregas do webhook), de onde pode ser reenviado. - A entrega é "pelo menos uma vez": o mesmo evento pode chegar mais de uma vez, sempre com o mesmo `id` (inclusive no reenvio pelo painel). Use `id` (`evt_...`) para ignorar repetidos. - A ordem não é garantida. Use `created_at` do envelope e `data.timestamp` do `message.status`. - Redirecionamentos não são seguidos. Headers: `Content-Type: application/json`, `X-Atalia-Event` (tipo), `X-Atalia-Event-Id` (id), `X-Atalia-Signature` e `User-Agent: Atalia-Webhooks/1.0`. Envelope (igual em todo evento): ```json { "id": "evt_9f2c4b1a7e3d5c6b8a0f1e2d", "type": "message.received", "created_at": "2026-10-28T17:02:11.482Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": { "id": "ch_2f81a9c0d1", "type": "whatsapp", "phone": "+55 11 98765-4321" }, "data": { } } ``` - `created_at` do envelope: ISO 8601 em UTC. `created_at` dentro de `data.message`: `"YYYY-MM-DD HH:MM:SS"` no horário de Brasília (o mesmo de `GET /messages/{id}`). - `channel`: `null` em `client.*` e `ping`. Identificador por tipo: `phone` (whatsapp, whatsapp_web), `username` (instagram), `page_name` (messenger). - `client_id`: só revenda; `null` nos seus próprios canais. Exemplos completos de cada evento (guia com tabelas de campos: https://chat.atalia.com.br/docs/integracao/eventos): `message.received` (mensagem do cliente; responda com `conversation_id`): ```json { "id": "evt_9f2c4b1a7e3d5c6b8a0f1e2d", "type": "message.received", "created_at": "2026-10-28T17:02:11.482Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": { "id": "ch_2f81a9c0d1", "type": "whatsapp", "phone": "+55 11 98765-4321" }, "data": { "conversation_id": "48213", "message": { "id": "6f1c2a7e-0b8e-4d0a-9a51-3f7c1e2d9b10", "external_id": "wamid.HBgNNTUxMTk4NzY1NDMyMRUCABIYFjNFQjA", "direction": "inbound", "type": "text", "content_type": null, "text": "Oi! Vocês entregam no centro hoje?", "media": null, "status": "delivered", "contact": { "name": "Maria Souza", "phone": "+5511988887777" }, "created_at": "2026-10-28 14:02:11" } } } ``` - `type`: `text`, `image`, `video`, `audio`, `document`, `sticker`, `interactive`, `template` e outros. `content_type: "interactive_button_reply"` quando o cliente tocou num botão (o título vem em `text`). - Mídia: `"media": { "mime_type": "image/jpeg", "download_path": "/api/v1/media/" }` e `text` = legenda. Baixe com `GET https://chat.atalia.com.br/api/v1/media/` + `x-api-key` (302 para link de 5 min; `409 MEDIA_PROCESSING` = tente de novo em segundos). - `template`: presente só quando `type` é `template` (e `text` é `null`). - Instagram e Messenger: `contact.phone` é `null`. `message.echo` (alguém respondeu pelo app: WhatsApp Business em coexistência, Instagram ou Messenger). Mesmo formato do `message.received`, com `"direction": "outbound"`: ```json { "id": "evt_0a1b2c3d4e5f6a7b8c9d0e1f", "type": "message.echo", "created_at": "2026-10-28T17:05:02.110Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": { "id": "ch_2f81a9c0d1", "type": "whatsapp", "phone": "+55 11 98765-4321" }, "data": { "conversation_id": "48213", "message": { "id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d", "external_id": "wamid.HBgNNTUxMTk4NzY1NDMyMRUCABEYEjQ5RkE", "direction": "outbound", "type": "text", "content_type": null, "text": "Oi, Maria! Aqui é a Carla, da loja.", "media": null, "status": "sent", "contact": { "name": "Maria Souza", "phone": "+5511988887777" }, "created_at": "2026-10-28 14:05:01" } } } ``` `message.status` (mensagem enviada pela API mudou de situação; `message_id` = `id` devolvido por `POST /messages`): ```json { "id": "evt_5d6e7f8a9b0c1d2e3f4a5b6c", "type": "message.status", "created_at": "2026-10-28T17:02:15.020Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": { "id": "ch_2f81a9c0d1", "type": "whatsapp", "phone": "+55 11 98765-4321" }, "data": { "message_id": "6f1c2a7e-0b8e-4d0a-9a51-3f7c1e2d9b10", "external_id": "wamid.HBgNNTUxMTk4NzY1NDMyMRUCABEYEjI3QjE", "status": "read", "timestamp": "2026-10-28T17:02:14.000Z", "errors": null } } ``` - `status`: `sent`, `delivered`, `read` ou `failed`. Em `failed`: `"errors": [{ "code": 131047, "title": "Re-engagement message" }]`. Instagram e Messenger mandam só `delivered` e `read`. `channel.connected` (`reconnected: true` quando o canal já existia): ```json { "id": "evt_1f2e3d4c5b6a7f8e9d0c1b2a", "type": "channel.connected", "created_at": "2026-10-28T16:40:00.000Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": { "id": "ch_2f81a9c0d1", "type": "whatsapp", "phone": "+55 11 98765-4321" }, "data": { "reconnected": false } } ``` `channel.disconnected` (canal apagado pelo painel ou por `DELETE /channels/{id}`; o `channel.id` deixa de existir; `unlinked` = resultado do desvínculo do número/conta no provedor: `meta` (WhatsApp) ou `zernio` (Instagram/Messenger) com `ok`, `failed` ou `skipped`): ```json { "id": "evt_2a3b4c5d6e7f8a9b0c1d2e3f", "type": "channel.disconnected", "created_at": "2026-10-29T12:00:00.000Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": { "id": "ch_2f81a9c0d1", "type": "whatsapp", "phone": "+55 11 98765-4321" }, "data": { "reason": "deleted", "unlinked": { "meta": "ok" } } } ``` `client.connected` (revenda; uma vez por cliente, quando ele aceita os termos e conecta o primeiro canal na página de conexão; canais seguintes chegam como `channel.connected` com o mesmo `client_id`; `ref` = o que veio no link `?ref=`, ou `null`): ```json { "id": "evt_3c4d5e6f7a8b9c0d1e2f3a4b", "type": "client.connected", "created_at": "2026-10-28T18:10:00.000Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": "c21a7f0e-2b4d-4e8a-9f1c-0d2e3f4a5b6c", "channel": null, "data": { "client": { "id": "c21a7f0e-2b4d-4e8a-9f1c-0d2e3f4a5b6c", "name": "Clínica Bem-Estar", "email": "contato@clinicabemestar.com.br", "tax_id": "11222333000181" }, "channels": ["whatsapp"], "ref": "usuario-8812" } } ``` `client.no_slot` (revenda; o cliente tentou conectar e o seu pacote estava cheio): ```json { "id": "evt_4d5e6f7a8b9c0d1e2f3a4b5c", "type": "client.no_slot", "created_at": "2026-10-28T18:12:00.000Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": "c21a7f0e-2b4d-4e8a-9f1c-0d2e3f4a5b6c", "channel": null, "data": { "client": { "id": "c21a7f0e-2b4d-4e8a-9f1c-0d2e3f4a5b6c", "name": "Clínica Bem-Estar", "email": "contato@clinicabemestar.com.br", "tax_id": "11222333000181" }, "ref": "usuario-8812" } } ``` `ping` (teste do painel ou de `POST /webhook/test`; responda 2xx e ignore): ```json { "id": "evt_5e6f7a8b9c0d1e2f3a4b5c6d", "type": "ping", "created_at": "2026-10-28T16:00:00.000Z", "company_id": "6b1f2c9e-4d3a-4c55-9a51-3f7c1e2d9b10", "client_id": null, "channel": null, "data": { "message": "Teste do webhook da Atalia" } } ``` ### Entregas do webhook O painel ("Entregas do webhook") guarda por 7 dias cada evento enviado: JSON, código HTTP, tempo, erro e o começo da resposta do seu sistema, com o botão Reenviar (mesmo `id`, assinatura nova). ### Verificar a assinatura `X-Atalia-Signature: t=,v1=`, onde `v1 = HMAC-SHA256(segredo, ".")`. O segredo (`whsec_...`) fica no painel, em "Segredo da assinatura". Calcule sobre o corpo CRU, antes de qualquer parse de JSON, e recuse `t` com mais de 5 minutos. ```js import crypto from 'node:crypto'; function verifyAtaliaSignature(rawBody, header, secret) { const parts = Object.fromEntries(header.split(',').map((p) => p.split('='))); if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false; const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex'); return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 || '')); } ``` ### POST /webhook/test Envia um `ping` agora e devolve o resultado: `{ "data": { "delivered": true, "event_id": "evt_...", "http_status": 200, "duration_ms": 182, "error": null } }`. ## Requisitos dos canais Guia completo (com o passo a passo da verificação da empresa na Meta): https://chat.atalia.com.br/docs/ajuda/requisitos-canais - Uso da API: sem contrato; basta concordar com os Termos de uso (https://atalia.com.br/termos-de-uso) e a Política de privacidade (https://atalia.com.br/politica-de-privacidade) da Atalia, e seguir as políticas da Meta (ex.: https://business.whatsapp.com/policy). - WhatsApp oficial: portfólio empresarial na Meta (business.facebook.com), de preferência verificado (sem verificação a Meta limita as conversas iniciadas pela empresa e pode recusar o nome de exibição); quem conecta é administrador do portfólio. Número novo (recebe código por SMS ou ligação; não pode estar em uso no app) ou coexistência (número que já está no app WhatsApp Business atualizado e continua registrado nele). - Instagram: conta profissional (Empresa ou Criador de conteúdo). Mensagens não chegando: no app, Ferramentas conectadas › Permitir acesso às mensagens. - Messenger: Página do Facebook publicada; quem conecta é administrador da Página. - Instagram e Messenger só respondem dentro de 24 horas da última mensagem do cliente. WhatsApp oficial fora de 24 horas: só template aprovado. ## Revenda: conectar os números dos seus clientes Para softwares cujos clientes conectam os próprios números. Modo "Integrar e oferecer aos meus clientes" (Configurações › Conta). Guia completo: https://chat.atalia.com.br/docs/integracao/clientes - Cada cliente vira uma conta filha ligada à sua. Os canais dele ocupam vagas do SEU pacote; você paga, recebe os eventos e envia pela SUA chave. - O cliente conecta pela sua Página de conexão (marca, cor, canais liberados; link em "Página de conexão › Link para enviar"). Três jeitos de levar o cliente: link geral (`/conectar/?ref=`), convite pelo painel (Clientes › Convidar cliente) ou convite pela API (abaixo). - Etapas que o cliente vê: "Sobre a sua empresa" (nome, CNPJ, e-mail E aceite dos termos da Atalia e, se cadastrados, os seus; os termos vêm ANTES de conectar) → um passo por canal (login do Facebook; no WhatsApp, "Número novo" ou "Coexistência", o número que já está no app do WhatsApp Business) → Concluir. - `client.connected` sai UMA vez por cliente, quando ele conecta o primeiro canal. Canais seguintes chegam como `channel.connected` com o mesmo `client_id`. - Um CNPJ que já tem canais não reabre a conta pelo link geral: para conectar mais canais, gere um link novo de convite para aquele cliente (painel ou `POST /clients/{id}/invite`). - Pacote cheio: o cliente vê uma mensagem pedindo para falar com você e chega `client.no_slot`. Libere vaga (canal avulso ou pacote maior) e mande o link de novo. - No seu sistema: guarde o `client.id` do `client.connected` junto do cadastro do cliente (case pelo `ref`, pelo `tax_id` ou pelo `email`). Todo evento de canal de cliente (`message.*`, `channel.*`) traz `client_id` no envelope; nos seus próprios canais é `null`. `GET /channels` lista os canais dos clientes com o `client_id`; para enviar, use o `channel_id` do canal do cliente. Para desconectar o canal de um cliente: `DELETE /channels/{channel_id}`. ### GET /clients Só revenda (senão `403 RESELLER_ONLY`). Lista os seus clientes: `{ "data": [ { "id", "name", "email", "tax_id", "ref", "status", "channels": ["whatsapp"], "created_at" } ] }`. `status`: `invited`, `in_progress` (preencheu os dados e aceitou os termos), `connected` (conectou pelo menos um canal) ou `no_slot`. ### POST /clients Cria o cliente e o link da sua página de conexão com os dados preenchidos (vale 7 dias). Exige a Página de conexão salva no painel (`409 CONNECT_PAGE_REQUIRED`). ```json { "name": "Clínica Bem-Estar", "email": "contato@clinicabemestar.com.br", "tax_id": "11222333000181", "ref": "usuario-8812", "send_email": false } ``` Responde `201`: `{ "data": { "client": { "id": "c21a...", "name": "...", "ref": "usuario-8812", "status": "invited", ... }, "connect_url": "https://conectar.atalia.ai/?i=", "email_sent": false } }`. `tax_id`, `ref` e `send_email` são opcionais. `ref`: até 200 caracteres, letras, números e `. _ : @ -`. Abra ou envie o `connect_url` para o seu usuário. ### POST /clients/{client_id}/invite Link novo para um cliente (o anterior deixa de valer), por exemplo para conectar mais um canal. Corpo opcional `{ "send_email": true }`. Responde `{ "data": { "connect_url": "...", "email_sent": false } }`. ### Voltar para o seu sistema (retorno da página) Com "Voltar para o seu sistema" preenchido no editor da página (exige webhook cadastrado), o navegador do cliente volta para o seu endereço: `?status=connected&client_id=&ref=&channels=whatsapp,instagram&t=&sig=` - `status`: `connected` (concluiu), `cancelled` (clicou em "Voltar para " antes de concluir; `client_id` pode faltar) ou `no_slot` (pacote cheio). - `sig` = HMAC-SHA256(segredo do webhook `whsec_...`, `"...."`), com os valores crus e vazio para o que faltar. Recuse `t` com mais de 5 minutos. - O retorno é para levar o usuário à tela certa; o dado oficial é o evento `client.connected` (chega mesmo se a pessoa fechar a página). - Implementação pronta: rota `GET /retorno` do projeto de exemplo (https://github.com/Atalia-IA/atalia-worker-template, arquivo src/connect-return.js). ```js function verifyAtaliaReturn(q, secret) { if (Math.abs(Date.now() / 1000 - Number(q.t)) > 300) return false; const base = `${q.t || ''}.${q.status || ''}.${q.client_id || ''}.${q.ref || ''}.${q.channels || ''}`; const expected = crypto.createHmac('sha256', secret).update(base).digest('hex'); return (q.sig || '').length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(q.sig)); } ``` ## Exemplo de ponta a ponta (curl) ```bash # 1. Descobrir o canal curl https://chat.atalia.com.br/api/v1/channels -H "x-api-key: $ATALIA_API_KEY" # 2. Enviar uma mensagem curl -X POST https://chat.atalia.com.br/api/v1/messages \ -H "x-api-key: $ATALIA_API_KEY" -H "Content-Type: application/json" \ -H "Idempotency-Key: pedido-1042-aviso" \ -d '{"channel_id":"ch_2f81a9c0d1","to":"+5511987654321","type":"text","text":"Olá!"}' ``` ## Projeto de exemplo Código aberto de um sistema completo sobre esta API, pronto para publicar na Cloudflare (Workers + D1 + Workers AI): https://github.com/Atalia-IA/atalia-worker-template - `POST /webhook`: confere a assinatura, ignora `evt_` repetido, grava e responde 200; a resposta da IA roda depois (`waitUntil`). - Agente simples: instruções, modelo e histórico configuráveis; palavras como "atendente" pausam o agente na conversa; `message.echo` (resposta pelo app) também pausa. - Resposta por `POST /messages` com `conversation_id` e `Idempotency-Key: reply-`; se outra mensagem do cliente chegou enquanto a IA pensava, só a mais nova é respondida. - Painel com senha: conversas, resposta manual, pausar/religar o agente, configuração do agente e diagnóstico da conexão (`GET /channels`, `POST /webhook/test`). - Guia: https://chat.atalia.com.br/docs/integracao/projeto-exemplo ## Boas práticas - Guarde a chave em variável de ambiente (ex.: `ATALIA_API_KEY`), nunca no código. - Responda o webhook rápido (grave o evento e processe depois) e confira a assinatura em todo evento. - Para responder um cliente, use o `conversation_id` do evento recebido. - Mensagens recebidas não passam por robôs nem por agentes de IA da Atalia neste modo: quem responde é o seu sistema.