API Externa
Integre o agente de IA do Feito aos seus próprios sistemas. Envie mensagens e receba respostas sugeridas pela IA via callback de webhook.
Visão Geral
A API Externa permite que você utilize as capacidades do agente de IA do Feito sem nossa integração com WhatsApp ou interface. Isso é útil para integrar respostas com IA em suas próprias plataformas de mensagens, CRMs ou aplicações personalizadas.
Como funciona
- 1Você envia uma mensagem para nossa API com o ID do contato e o conteúdo da mensagem
- 2Nossa IA processa a conversa e gera uma resposta sugerida
- 3Enviamos a resposta para sua URL de webhook para você processar
Autenticação
Todas as requisições à API requerem autenticação usando um Bearer token.
Já é cliente? Gere sua chave em Configurações da Conta. Se não, fale com a gente.
Authorization: Bearer fsk_sua_chave_api_aquiFormato da Chave API
As chaves API começam com fsk_ seguido de uma string aleatória. Mantenha sua chave segura e nunca a exponha em código do lado do cliente.
Enviar Mensagem
/api/v1/repliesEnvie uma mensagem de um contato para obter uma resposta sugerida pela IA. A resposta será entregue de forma assíncrona para sua URL de webhook.
Parâmetros da Requisição
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
contactId | string | Sim | Seu identificador único para este contato. Usado para manter o histórico da conversa. |
message | string | Sim | A mensagem recebida do contato. |
contactName | string | Não | Nome de exibição do contato. Atualizado a cada requisição, se fornecido. |
webhookUrl | string | Não | Sobrescreve a URL de webhook padrão para esta requisição. |
Exemplo de Requisição
curl -X POST https://feito.io/api/v1/replies \
-H "Authorization: Bearer fsk_sua_chave_api" \
-H "Content-Type: application/json" \
-d '{
"contactId": "user_123",
"contactName": "João Silva",
"message": "Olá, gostaria de agendar uma consulta"
}'Resposta
Retorna imediatamente com um ID do job. A resposta real será enviada para seu webhook.
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued"
}Formato de Eventos
Quando o processamento é concluído, fazemos um POST do resultado para sua URL de webhook usando um formato padronizado de eventos. Todos os webhooks seguem a mesma estrutura de envelope.
Estrutura do Evento
{
"id": "evt_abc123def456",
"type": "reply.generated",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00.000Z",
"account_id": "acc_xyz789",
"data": {
"object": { ... }
}
}Campos do Envelope
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | string | Sim | ID único do evento (prefixo: evt_). Use para idempotência. |
type | string | Sim | Tipo do evento (ex: reply.generated, reply.skipped). |
api_version | string | Sim | Versão da API no formato YYYY-MM-DD. |
created_at | string | Sim | Timestamp ISO 8601 de quando o evento foi criado. |
account_id | string | Sim | ID da conta que gerou este evento. |
data.object | object | Sim | Payload específico do tipo de evento. |
Cabeçalhos do Webhook
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
X-Feito-Event | string | Sim | Tipo do evento (ex: reply.generated). |
X-Feito-Request-Id | string | Sim | ID único do evento. |
X-Feito-Timestamp | string | Sim | Timestamp Unix da requisição. |
X-Feito-Signature | string | Não | Assinatura HMAC-SHA256 (se segredo configurado). |
Tipos de Eventos
Diferentes tipos de eventos são enviados dependendo do resultado do processamento da IA.
reply.generated
A IA gerou uma resposta com sucesso.
{
"id": "evt_abc123def456",
"type": "reply.generated",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00.000Z",
"account_id": "acc_xyz789",
"data": {
"object": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": "user_123",
"reply": "Olá João! Claro, ficarei feliz em ajudá-lo...",
"confidence": 0.92
}
}
}reply.skipped
A IA determinou que nenhuma resposta é necessária (ex: o contato apenas disse "ok" ou "obrigado").
{
"id": "evt_abc456def789",
"type": "reply.skipped",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00.000Z",
"account_id": "acc_xyz789",
"data": {
"object": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": "user_123",
"reason": "Contato confirmou mensagem anterior"
}
}
}reply.blocked
A resposta foi bloqueada por guardrails de segurança.
{
"id": "evt_abc789def101",
"type": "reply.blocked",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00.000Z",
"account_id": "acc_xyz789",
"data": {
"object": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": "user_123",
"reason": "Mensagem continha conteúdo proibido",
"violations": ["pricing_commitment"]
}
}
}reply.failed
O processamento falhou devido a um erro.
{
"id": "evt_abcdef123456",
"type": "reply.failed",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00.000Z",
"account_id": "acc_xyz789",
"data": {
"object": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": "user_123",
"error": "Timeout na orquestração"
}
}
}Verificação de Assinatura
Se você configurou um segredo de webhook, verifique a autenticidade das requisições usando a assinatura HMAC-SHA256.
Formato da Assinatura
A assinatura é calculada sobre timestamp.payload e enviada no header com o prefixo sha256=.
Exemplo de Verificação
const crypto = require('crypto');
function verifyWebhookSignature(req, secret) {
const signature = req.headers['x-feito-signature'];
const timestamp = req.headers['x-feito-timestamp'];
const payload = JSON.stringify(req.body);
// Verifica se timestamp está dentro de 5 minutos
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
return false; // Replay attack prevention
}
// Calcula assinatura esperada
const signedPayload = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Extrai valor da assinatura (remove prefixo sha256=)
const sigValue = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(sigValue),
Buffer.from(expected)
);
}Importante
Sempre verifique o timestamp para prevenir ataques de replay. Rejeite requisições com timestamps mais antigos que 5 minutos.
Tratamento de Erros
A API usa códigos de status HTTP padrão. Respostas de erro incluem uma mensagem descritiva.
Códigos de Status HTTP
| Status | Descrição |
|---|---|
202 | Requisição aceita e enfileirada para processamento |
400 | Requisição inválida — parâmetros ausentes ou inválidos |
401 | Não autorizado — chave API inválida ou ausente |
500 | Erro interno do servidor |
Formato de Resposta de Erro
{
"error": "contactId is required"
}Falhas de Webhook
Se não conseguirmos entregar ao seu webhook, tentaremos novamente com backoff exponencial. Entregas com falha são visíveis na visualização da conversa:
Olá, quero saber mais sobre seus serviços
21:54
Olá, João! Tudo bem? Que ótimo receber seu contato. Nós ajudamos profissionais e empresas a economizar tempo e agendar mais clientes, usando uma inteligência artificial que responde e qualifica os interessados no seu WhatsApp 24h por dia. Para eu te ajudar melhor, me conta: qual é o seu maior desafio hoje ao usar o WhatsApp para o seu negócio?
21:55
A mensagem de erro mostra o motivo da falha na entrega do webhook. Causas comuns incluem URLs inacessíveis, problemas de certificado SSL ou timeouts.