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.
Leads
Gerencie leads programaticamente. Você pode buscar leads existentes e criar novos leads de forma idempotente.
Buscar Lead
/api/v1/leads— Buscar lead por telefoneParâmetros de Query
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
phone | string | Sim | Número de telefone no formato E.164 (ex: +5511999999999) |
Exemplo de Requisição
curl -X GET "https://feito.io/api/v1/leads?phone=%2B5511999999999" \
-H "Authorization: Bearer fsk_sua_chave_api"Resposta (200)
{
"lead": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"phone": "+5511999999999",
"contactId": "crm_123",
"name": "João Silva",
"state": "active",
"handler": "ai",
"createdAt": "2024-01-15T10:00:00Z"
}
}Resposta (404)
{
"error": "Lead not found"
}Criar Lead
/api/v1/leads— Criar ou retornar lead existenteCrie um novo lead ou retorne um existente (idempotente). Se um lead com o mesmo phone ou contactId já existir, ele será retornado.
Parâmetros da Requisição
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
contactId | string | Sim | Seu identificador externo para o contato (ex: ID do CRM) |
phone | string | Não | Número de telefone no formato E.164. Necessário para enviar templates. |
name | string | Não | Nome de exibição do contato. |
Exemplo de Requisição
curl -X POST https://feito.io/api/v1/leads \
-H "Authorization: Bearer fsk_sua_chave_api" \
-H "Content-Type: application/json" \
-d '{
"contactId": "crm_123",
"phone": "+5511999999999",
"name": "João Silva"
}'Resposta (201 - Lead criado)
{
"lead": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"phone": "+5511999999999",
"contactId": "crm_123",
"name": "João Silva",
"state": "new",
"handler": "ai",
"createdAt": "2024-01-15T10:00:00Z"
},
"created": true
}Resposta (200 - Lead existente)
{
"lead": { ... },
"created": false
}Webhook lead.created
Quando um novo lead é criado (de qualquer fonte: API, dashboard ou WhatsApp), um evento lead.created é enviado para seu webhook. Veja mais detalhes na seção Tipos de Eventos.
Enviar Template
/api/v1/leads/:id/send-template— Enviar mensagem template aprovadaEnvie uma mensagem de template aprovado pelo WhatsApp para um lead. Útil para iniciar conversas fora da janela de 24 horas ou para mensagens padronizadas.
Parâmetros de URL
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | string | Sim | UUID do lead no Feito. |
Parâmetros da Requisição
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
template_name | string | Sim | Nome técnico do template aprovado. |
variables | object | Não | Valores das variáveis por posição (ex: {"1": "João", "2": "Empresa XYZ"}). |
Exemplo de Requisição
curl -X POST https://feito.io/api/v1/leads/550e8400.../send-template \
-H "Authorization: Bearer fsk_sua_chave_api" \
-H "Content-Type: application/json" \
-d '{
"template_name": "welcome_message",
"variables": {
"1": "João",
"2": "Empresa XYZ"
}
}'Resposta (200)
{
"success": true,
"messageSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}Erros Comuns
| Status | Descrição |
|---|---|
400 | Lead não tem telefone válido (foi criado apenas com contactId) |
400 | Template não está aprovado |
403 | Lead não pertence a esta conta |
404 | Lead ou template não encontrado |
Requisito de Telefone
Para enviar templates, o lead deve ter um número de telefone válido. Leads criados apenas com contactId (sem phone) não podem receber templates.
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.
Eventos de Lead
lead.created
Disparado quando um novo lead é criado de qualquer fonte (API externa, dashboard ou mensagem de WhatsApp).
{
"id": "evt_xyz789abc123",
"type": "lead.created",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00.000Z",
"account_id": "acc_xyz789",
"data": {
"object": {
"lead_id": "550e8400-e29b-41d4-a716-446655440000",
"external_id": "crm_123",
"phone": "+5511999999999",
"profile_name": "João Silva",
"source": "external_api"
}
}
}Campos do Evento lead.created
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
lead_id | string | Sim | UUID interno do lead no Feito. |
external_id | string | Não | Seu contactId (se fornecido na criação). |
phone | string | Sim | Número de telefone (ou placeholder ext_* se não fornecido). |
profile_name | string | Não | Nome de exibição do lead. |
source | string | Sim | Origem: external_api, dashboard ou whatsapp_inbound. |
Eventos de Resposta
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.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.
