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_3f9a2c1b7d4e6a8c0b2d4f6a8c0e2b4d6f8a0c2e

Guarde 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

CampoObrigatórioDescrição
numerosimTelefone do lead. Aceita +55 (11) 99999-9999, 5511999999999 ou 11999999999.
agenteIdnãoQual dos seus agentes atende essa ligação. Sem ele, entra o agente principal da conta.
referencianãoTexto 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 depois

PHP (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ódigoErroO que fazer
400NUMERO_INVALIDOO telefone não virou um número brasileiro válido. Confira DDD e dígitos.
403SO_DEMOA conta ainda não está liberada para colocar ligação no ar. Fale com quem cuida da sua conta.
404AGENTE_NAO_ENCONTRADOO agenteId não é um agente da sua conta.
429LIMITEVocê 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á

ValorSignificado
na_filaAceita, esperando a vez (ou esperando a janela de horário abrir).
discandoO telefone está tocando ou a conversa está rolando.
atendeuA pessoa atendeu e conversou com o agente.
caixa_postalCaiu na caixa de mensagens.
nao_atendeuNingué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

EventoQuando dispara
ligacao.finalizadaUma ligação terminou e o custo já está fechado.
campanha.concluidaUma lista de contatos terminou de ser discada.
sms.enviadoSaiu o SMS de pós-ligação daquele contato.
conversa.contatoO 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.marcadaO agente marcou uma reunião na sua agenda conectada. Traz nome, telefone, e-mail, assunto, inicio/fim (ISO), fuso e o link do compromisso.
testeVocê 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

HeaderConteúdo
Content-Typeapplication/json
User-AgentAlfredVoice-Avisos/1
X-Alfred-EventoNome do evento (ligacao.finalizada, …)
X-Alfred-EntregaIdentificador único da entrega (o mesmo entrega_id do corpo)
X-Alfred-Assinaturasha256=<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 depois

Repetiçã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 200 primeiro 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 header X-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"}.

HTTPCódigoSignificado
400NUMERO_INVALIDOO telefone enviado não é um número brasileiro válido.
400URL_INVALIDAA URL do aviso automático não passou nas regras (https, domínio, até 500 caracteres).
400NOME_INVALIDONome da chave de API vazio ou com mais de 60 caracteres.
401NAO_AUTORIZADOChave inexistente, revogada ou de uma conta desativada.
403SO_DEMOA conta ainda não está liberada para colocar ligação no ar.
403SO_SESSAOEsse endereço só abre para quem está logado no painel — chave de API não entra.
404AGENTE_NAO_ENCONTRADOO agenteId não pertence à sua conta.
404NAO_ENCONTRADOO recurso não existe ou não é seu.
409LIMITE_CHAVESVocê já tem 5 chaves ativas.
429LIMITEPassou do teto de requisições da chave. Veja o header Retry-After.
500ERRO_INTERNODeu 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

LimiteValor
Requisições por chave120 por minuto (janela deslizante). Ao estourar: 429 LIMITE + Retry-After em segundos.
Chaves ativas por conta5
referencia120 caracteres (o que passar disso é cortado)
URL do aviso automático500 caracteres
limite em GET /ligacoes1 a 200 (padrão 50)
Resposta do seu servidor ao aviso8 segundos
Números por campanhalistas 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:

  1. Crie a chave em Conta → Chaves de API.
  2. Rode o GET /me do passo 2 e confirme que a chave responde.
  3. Cadastre o aviso automático em Conta → Aviso automático apontando para o seu servidor e mande o aviso de teste.
  4. Faça um POST /ligacoes com o seu próprio celular e a referencia que quiser. Atenda, converse com o agente e desligue.
  5. Confira o ligacao.finalizada que 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.