Integração — Alfred Voice
O Alfred Voice é um agente de voz que liga para os seus contatos e conversa com eles. Esta API existe para duas coisas: pedir uma ligação assim que um lead chega no seu site e receber o resultado de volta no seu sistema.
- Base:
https://alfredvoice.com.br/api - Autenticação: header
Authorization: Bearer av_...(sua chave de API) - Formato: JSON em tudo, entrada e saída (
Content-Type: application/json) - Erros: sempre no mesmo envelope —
{"error":"CODIGO"}— com o código HTTP correspondente
Vai atender os seus próprios clientes pelo seu sistema (contas separadas, saldo por cliente, WhatsApp, torpedo de voz e SMS em nome deles)? Veja também a Revenda por API.
Ligações reais saem entre 8h e 20h (horário de Brasília). Um pedido feito fora dessa janela fica guardado na fila e sai junto com o próximo pedido que você fizer dentro do horário.
1. Crie sua chave de API
No painel: Conta → Chaves de API → Nova chave. Dê um nome que lembre onde ela vai morar (Site institucional, CRM, Landing de captação).
A chave completa aparece uma única vez, na tela da criação:
av_3f9a2c1b7d4e6a8c0b2d4f6a8c0e2b4d6f8a0c2eGuarde num cofre de segredos ou numa variável de ambiente do seu servidor. Depois disso o painel só mostra o prefixo (av_3f9a2c1) para você reconhecer qual chave é qual. Se perdeu, crie outra e revogue a antiga.
Regras:
- Até 5 chaves ativas por conta. A sexta responde
409 LIMITE_CHAVES— revogue uma que não usa mais. - Revogar vale na hora: a chave revogada passa a responder
401 NAO_AUTORIZADO. - A chave nunca entra no navegador nem em app de celular. Ela vale como senha: quem tem a chave pede ligação na sua conta e gasta o seu saldo. Use só de servidor para servidor.
- A chave não administra a própria conta: criar/revogar chaves e cadastrar o aviso automático são coisas de quem está logado no painel.
2. Teste a chave
curl https://alfredvoice.com.br/api/me \
-H "Authorization: Bearer av_3f9a2c1b7d4e6a8c0b2d4f6a8c0e2b4d6f8a0c2e"Resposta:
{
"id": 12,
"email": "voce@suaempresa.com.br",
"nome": "Sua Empresa",
"papel": "cliente",
"persona": { "id": "yasmin", "nome": "Yasmin", "voz": "feminina", "avatar": "yasmin.png" }
}Se vier 401 {"error":"NAO_AUTORIZADO"}, a chave está errada, foi revogada ou o header não chegou como Bearer <chave>.
Aproveite e confira o panorama da conta:
curl https://alfredvoice.com.br/api/resumo \
-H "Authorization: Bearer av_..."{
"hoje": { "ligacoes": 34, "atendidas": 12, "custoCentavos": 688, "sms": 4 },
"campanhasAtivas": 1,
"agentes": 2,
"totalLigacoes": 1907,
"ultimaLigacaoEm": "2026-09-04 16:12:41"
}3. Peça uma ligação
POST /ligacoes coloca o número na fila e o agente liga em seguida.
Corpo
| Campo | Obrigatório | Descrição |
|---|---|---|
numero | sim | Telefone do lead. Aceita +55 (11) 99999-9999, 5511999999999 ou 11999999999. |
agenteId | não | Qual dos seus agentes atende essa ligação. Sem ele, entra o agente principal da conta. |
referencia | não | Texto livre de até 120 caracteres, seu identificador do lead. Volta em todas as respostas e avisos. |
referencia: o campo que amarra tudo
Guarde ali o id do lead no seu banco (lead-8842, crm-90210, form-orcamento-77). Você não precisa guardar o id que devolvemos: quando o resultado da ligação chegar no seu sistema, a referencia diz na hora de quem era aquela conversa.
curl
curl -X POST https://alfredvoice.com.br/api/ligacoes \
-H "Authorization: Bearer av_3f9a2c1b7d4e6a8c0b2d4f6a8c0e2b4d6f8a0c2e" \
-H "Content-Type: application/json" \
-d '{"numero":"+55 (11) 99999-9999","referencia":"lead-8842"}'Node 18+ (fetch nativo)
const resposta = await fetch('https://alfredvoice.com.br/api/ligacoes', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ALFRED_VOICE_CHAVE}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
numero: lead.telefone,
referencia: `lead-${lead.id}`,
}),
});
if (resposta.status !== 202) {
const erro = await resposta.json();
throw new Error(`Alfred Voice recusou: ${erro.error}`);
}
const ligacao = await resposta.json();
// guarde ligacao.id se quiser consultar depoisPHP (curl)
<?php
$dados = json_encode([
'numero' => $lead['telefone'],
'referencia' => 'lead-' . $lead['id'],
]);
$ch = curl_init('https://alfredvoice.com.br/api/ligacoes');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $dados,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('ALFRED_VOICE_CHAVE'),
'Content-Type: application/json',
],
]);
$corpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($codigo !== 202) {
$erro = json_decode($corpo, true);
throw new RuntimeException('Alfred Voice recusou: ' . ($erro['error'] ?? 'desconhecido'));
}
$ligacao = json_decode($corpo, true);Resposta `202 Accepted`
{ "id": 4821, "numero": "5511999999999", "campanhaId": 37, "status": "na_fila" }202 quer dizer "aceitamos o pedido e vamos ligar", não "já ligamos". O id é o identificador da ligação nesta API — use nos passos seguintes.
Todas as ligações pedidas por aqui ficam numa lista de sistema chamada API · Ligar agora, que você também vê no painel, em Contatos.
Erros deste endpoint
| Código | Erro | O que fazer |
|---|---|---|
| 400 | NUMERO_INVALIDO | O telefone não virou um número brasileiro válido. Confira DDD e dígitos. |
| 403 | SO_DEMO | A conta ainda não está liberada para colocar ligação no ar. Fale com quem cuida da sua conta. |
| 404 | AGENTE_NAO_ENCONTRADO | O agenteId não é um agente da sua conta. |
| 429 | LIMITE | Você passou do teto de requisições. Respeite o header Retry-After. |
4. Acompanhe o resultado
curl https://alfredvoice.com.br/api/ligacoes/4821 \
-H "Authorization: Bearer av_..."{
"id": 4821,
"numero": "5511999999999",
"referencia": "lead-8842",
"status": "atendeu",
"chamada": {
"chamada_id": "cmp37-4821",
"atendida": true,
"resultado": "atendeu",
"duracao_seg": 74,
"custo_centavos": 59,
"created_at": "2026-09-04 16:12:41"
}
}Enquanto a ligação não terminou, chamada vem null.
`status` — onde a ligação está
| Valor | Significado |
|---|---|
na_fila | Aceita, esperando a vez (ou esperando a janela de horário abrir). |
discando | O telefone está tocando ou a conversa está rolando. |
atendeu | A pessoa atendeu e conversou com o agente. |
caixa_postal | Caiu na caixa de mensagens. |
nao_atendeu | Ninguém atendeu, ou a linha recusou. |
`resultado` — como terminou
Mesmos três desfechos finais: atendeu, caixa_postal, nao_atendeu. atendida é o mesmo desfecho em booleano, para você não precisar comparar texto.
`duracao_seg` é o tempo de conversa (zero quando ninguém atendeu) e `custo_centavos` é o que aquela ligação custou — cobramos só ligação atendida.
Últimas ligações
curl "https://alfredvoice.com.br/api/ligacoes?limite=50" \
-H "Authorization: Bearer av_..."{ "ligacoes": [ { "id": 4821, "numero": "...", "referencia": "...", "status": "atendeu", "chamada": { } } ] }limite vai de 1 a 200 (padrão 50), da mais nova para a mais antiga.
Sobre consultar em laço: se for perguntar de tempos em tempos, pergunte no máximo a cada 30 segundos por ligação, e pare de perguntar quando chamada deixar de ser null. Melhor ainda: não pergunte — cadastre o aviso automático do passo 5 e deixe o resultado chegar sozinho.
5. Receba avisos automáticos
Em vez de consultar, receba: você cadastra um endereço https:// seu e a gente faz um POST nele toda vez que algo acontece na sua conta.
Cadastro
No painel: Conta → Aviso automático. Cole a URL, salve e copie o segredo (whs_...) que aparece na hora — ele serve para você conferir que o aviso veio mesmo de nós. Como a chave de API, o segredo aparece uma vez só; salvar a URL de novo gera um segredo novo.
Regras da URL: https:// obrigatório, endereço com nome de domínio (não aceitamos IP solto), até 500 caracteres. URL fora dessas regras responde 400 URL_INVALIDA. Na mesma tela tem o botão de enviar um aviso de teste e a lista das últimas entregas com o código que o seu servidor devolveu.
Eventos
| Evento | Quando dispara |
|---|---|
ligacao.finalizada | Uma ligação terminou e o custo já está fechado. |
campanha.concluida | Uma lista de contatos terminou de ser discada. |
sms.enviado | Saiu o SMS de pós-ligação daquele contato. |
conversa.contato | O agente colheu nome, telefone ou e-mail de quem falou com ele no site ou no WhatsApp (uma vez por conversa). Traz o contato e as últimas falas. |
reuniao.marcada | O agente marcou uma reunião na sua agenda conectada. Traz nome, telefone, e-mail, assunto, inicio/fim (ISO), fuso e o link do compromisso. |
teste | Você clicou em enviar aviso de teste no painel. |
Formato do aviso
Todo aviso chega com o mesmo envelope:
{
"evento": "ligacao.finalizada",
"entrega_id": "8f14e45f-ceea-467a-9c2e-6b1d2b8a3f41",
"enviado_em": "2026-09-04T19:12:44.918Z",
"dados": {
"ligacao_id": 4821,
"campanha_id": 37,
"campanha_nome": "API · Ligar agora",
"numero": "5511999999999",
"referencia": "lead-8842",
"agente_id": 5,
"agente_nome": "Comercial",
"atendida": true,
"resultado": "atendeu",
"duracao_seg": 74,
"custo_centavos": 59,
"iniciada_em": "2026-09-04 16:11:18"
}
}dados de campanha.concluida:
{ "campanha_id": 41, "campanha_nome": "Base setembro", "total": 500, "atendidas": 214, "caixa_postal": 96, "nao_atendeu": 190 }dados de sms.enviado:
{ "ligacao_id": 4821, "campanha_id": 37, "numero": "5511999999999", "referencia": "lead-8842" }dados de teste:
{ "mensagem": "Aviso de teste do Alfred Voice" }Headers
| Header | Conteúdo |
|---|---|
Content-Type | application/json |
User-Agent | AlfredVoice-Avisos/1 |
X-Alfred-Evento | Nome do evento (ligacao.finalizada, …) |
X-Alfred-Entrega | Identificador único da entrega (o mesmo entrega_id do corpo) |
X-Alfred-Assinatura | sha256=<HMAC-SHA256 do corpo cru, em hex, com o seu segredo> |
Confira a assinatura
Calcule o HMAC-SHA256 do corpo cru (os bytes exatos que chegaram, antes de qualquer JSON.parse) usando o seu segredo, e compare com o header em tempo constante. Comparação com == abre brecha para descobrir a assinatura tentativa por tentativa.
Node
const crypto = require('node:crypto');
const express = require('express');
const app = express();
// corpo CRU: a assinatura é dos bytes que chegaram, não do objeto já convertido
app.post('/avisos', express.raw({ type: 'application/json' }), (req, res) => {
const esperado = 'sha256=' + crypto.createHmac('sha256', process.env.ALFRED_VOICE_SEGREDO)
.update(req.body).digest('hex');
const recebida = String(req.get('X-Alfred-Assinatura') || '');
const a = Buffer.from(esperado, 'utf8');
const b = Buffer.from(recebida, 'utf8');
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).end();
}
const aviso = JSON.parse(req.body.toString('utf8'));
// responda rápido; guarde o aviso e processe depois
res.status(200).json({ ok: true });
processarDepois(aviso);
});PHP
<?php
$corpo = file_get_contents('php://input');
$esperado = 'sha256=' . hash_hmac('sha256', $corpo, getenv('ALFRED_VOICE_SEGREDO'));
$recebida = $_SERVER['HTTP_X_ALFRED_ASSINATURA'] ?? '';
if (!hash_equals($esperado, $recebida)) {
http_response_code(401);
exit;
}
$aviso = json_decode($corpo, true);
http_response_code(200);
// guarde e processe depoisRepetição e reenvio
- Sucesso é qualquer resposta 2xx. Qualquer outra coisa — 4xx, 5xx, tempo esgotado, servidor fora do ar — conta como falha.
- Damos ao seu servidor 8 segundos para responder. Responda
200primeiro e faça o trabalho pesado depois. - Falhou? Tentamos de novo em 30 segundos, depois em 5 minutos, depois em 30 minutos. São 1 envio mais 3 tentativas; depois disso a entrega é marcada como falha e aparece na lista de entregas do painel.
- O mesmo aviso pode chegar mais de uma vez. O
entrega_id(corpo e headerX-Alfred-Entrega) é único e imutável entre as tentativas: guarde os que já processou e ignore repetidos. O corpo também não muda entre as tentativas — por isso a assinatura continua válida. - Se o seu servidor cair no meio, nada se perde: as entregas pendentes voltam para a agenda.
6. Campanhas em lote pela API
Quando não é um lead por vez e sim uma lista inteira, use campanhas. As mesmas chaves de API valem aqui.
Criar a lista
curl -X POST https://alfredvoice.com.br/api/campanhas \
-H "Authorization: Bearer av_..." \
-H "Content-Type: application/json" \
-d '{"nome":"Base setembro","numeros":["11999990001","+55 (21) 98888-0002"],"agenteId":5}'{ "id": 41, "nome": "Base setembro", "status": "rascunho", "total": 2, "descartados": 0 }descartados conta o que não parecia telefone e ficou de fora. agenteId é opcional.
Colocar para discar
curl -X POST https://alfredvoice.com.br/api/campanhas/41/discar \
-H "Authorization: Bearer av_..."{ "ok": true }Erros: 403 SO_DEMO (conta não liberada), 409 JA_DISCANDO (essa lista já está no ar), 404 NAO_ENCONTRADO.
Ver como está indo
curl https://alfredvoice.com.br/api/campanhas/41 \
-H "Authorization: Bearer av_..."{
"id": 41,
"nome": "Base setembro",
"status": "discando",
"modo": "real",
"agente": { "id": 5, "nome": "Comercial", "voz": "feminina" },
"numeros": [ { "numero": "5511999990001", "status": "atendeu" } ],
"resumo": { "total": 500, "feitas": 218, "atendidas": 96, "custoTotalCentavos": 4712 }
}status da campanha: rascunho, discando, pausada, concluida.
Ligações da campanha
curl https://alfredvoice.com.br/api/campanhas/41/ligacoes \
-H "Authorization: Bearer av_..."[
{ "chamadaId": "cmp41-903", "numero": "5511999990001", "resultado": "atendeu",
"duracaoSeg": 74, "custoCentavos": 59, "faixa": "cheia", "quando": "2026-09-04 16:12:41" }
]faixa é como aquela ligação foi tarifada: cheia, reduzida (a sobra de minuto curta sai mais barata) ou zero (não atendeu, não cobra).
Parar
curl -X POST https://alfredvoice.com.br/api/campanhas/41/parar \
-H "Authorization: Bearer av_..."{ "ok": true }A campanha para no próximo contato: as ligações que já estavam no ar terminam normalmente. Para retomar, é só mandar discar de novo — quem já foi discado não repete.
Tabela de erros
Todo erro vem como {"error":"CODIGO"}.
| HTTP | Código | Significado |
|---|---|---|
| 400 | NUMERO_INVALIDO | O telefone enviado não é um número brasileiro válido. |
| 400 | URL_INVALIDA | A URL do aviso automático não passou nas regras (https, domínio, até 500 caracteres). |
| 400 | NOME_INVALIDO | Nome da chave de API vazio ou com mais de 60 caracteres. |
| 401 | NAO_AUTORIZADO | Chave inexistente, revogada ou de uma conta desativada. |
| 403 | SO_DEMO | A conta ainda não está liberada para colocar ligação no ar. |
| 403 | SO_SESSAO | Esse endereço só abre para quem está logado no painel — chave de API não entra. |
| 404 | AGENTE_NAO_ENCONTRADO | O agenteId não pertence à sua conta. |
| 404 | NAO_ENCONTRADO | O recurso não existe ou não é seu. |
| 409 | LIMITE_CHAVES | Você já tem 5 chaves ativas. |
| 429 | LIMITE | Passou do teto de requisições da chave. Veja o header Retry-After. |
| 500 | ERRO_INTERNO | Deu errado do nosso lado. Tente de novo; se insistir, fale com o suporte. |
Nunca devolvemos trilha de erro nem detalhe interno no corpo — se precisar investigar, o código do erro e o horário da requisição bastam para o suporte achar.
Limites
| Limite | Valor |
|---|---|
| Requisições por chave | 120 por minuto (janela deslizante). Ao estourar: 429 LIMITE + Retry-After em segundos. |
| Chaves ativas por conta | 5 |
referencia | 120 caracteres (o que passar disso é cortado) |
| URL do aviso automático | 500 caracteres |
limite em GET /ligacoes | 1 a 200 (padrão 50) |
| Resposta do seu servidor ao aviso | 8 segundos |
| Números por campanha | listas grandes são bem-vindas; envie o array completo numa requisição só |
Segure os 429: ao receber, espere o que o Retry-After mandar antes de tentar de novo. Uma fila simples do seu lado, com uma requisição por vez, já resolve a maioria dos casos.
Comece com o seu crédito de teste
Toda conta nova ganha R$ 5 em créditos ao confirmar o e-mail — o suficiente para fechar o ciclo inteiro sem gastar nada:
- Crie a chave em Conta → Chaves de API.
- Rode o
GET /medo passo 2 e confirme que a chave responde. - Cadastre o aviso automático em Conta → Aviso automático apontando para o seu servidor e mande o aviso de teste.
- Faça um
POST /ligacoescom o seu próprio celular e areferenciaque quiser. Atenda, converse com o agente e desligue. - Confira o
ligacao.finalizadaque chegou no seu servidor: número,referencia, desfecho, duração e custo.
Fechou esse ciclo, a integração está pronta — o resto é ligar no seu formulário de leads.