Revenda por API — Alfred Voice

Esta página é para quem vai colocar o Alfred Voice dentro do próprio sistema (um CRM, uma plataforma de atendimento) e oferecer para os seus clientes: agentes de IA no WhatsApp e no site, ligação com agente, torpedo de voz e SMS.

A ideia em uma frase: você tem uma conta de revendedor; cada cliente seu vira uma subconta; você age em nome de qualquer subconta mandando um header.

  • Base: https://alfredvoice.com.br/api
  • Autenticação: Authorization: Bearer av_... (a chave de API da sua conta de revendedor)
  • Agir em nome de um cliente seu: header X-Subconta: <id da subconta>
  • Formato: JSON em tudo (Content-Type: application/json), exceto o envio de arquivo de áudio
  • Erros: sempre {"error":"CODIGO"} com o código HTTP correspondente (tabela completa na seção 15)
  • Dinheiro: sempre em centavos inteiros (5000 = R$ 50,00)
  • Datas: em UTC, no formato AAAA-MM-DD HH:MM:SS
  • Para o seu desenvolvedor começar rápido: baixe o arquivo de integração (botão no menu ao lado) e importe no Postman ou Insomnia — explicado em Arquivo de integração

A parte básica (criar chave, testar a chave, assinatura dos avisos, reenvio) está em Integração por API. Esta página cobre tudo o que é próprio da revenda.


1. Como funciona

Sua conta de revendedor ── saldo (você recarrega por PIX no painel)
  ├── Subconta "Pizzaria do João"   ── agentes, WhatsApp, balão do site, torpedos, SMS, saldo próprio
  ├── Subconta "Clínica Sorriso"    ── idem
  └── ...
  1. Você recarrega a sua conta pelo painel (Carteira → Recarregar, PIX na hora).
  2. Cria uma subconta para cada cliente seu, com o id que ele tem no seu sistema (referencia).
  3. Transfere saldo da sua conta para a subconta. O consumo do cliente sai do saldo dele — um cliente nunca gasta o saldo de outro.
  4. Opera em nome do cliente mandando X-Subconta nas rotas: criar agente, conectar o WhatsApp, ligar o balão do site, disparar torpedo, mandar SMS, ler as conversas.
  5. Recebe tudo no seu servidor por aviso automático, com a subconta identificada.
  6. Consulta o consumo de cada cliente no período e fatura ele como quiser. O preço que você cobra do seu cliente é decisão sua; do nosso lado a tarifa é a da sua conta.

Os seus clientes não têm login no Alfred Voice: eles só existem pelo seu sistema. No painel, o menu Revenda mostra os seus clientes, o saldo de cada um e o consumo, para você conferir e resolver na mão.


2. Antes de começar

  • Revenda liberada: a conta precisa estar com a revenda ligada pela nossa equipe. Sem isso, as rotas de revenda respondem 403 SEM_REVENDA.
  • Chave de API: crie em Conta → Chaves de API (a chave aparece uma vez só). Até 5 chaves ativas; use uma para testes e outra para produção.
  • Aviso automático: cadastre em Conta → Aviso automático a URL https:// que vai receber os eventos. Os eventos de todas as suas subcontas chegam nela (seção 13).
  • Teste com o seu próprio celular antes de pôr cliente real (roteiro na seção 17).

Arquivo de integração (Postman / Insomnia)

Além desta página, existe um arquivo de integração: é a lista de todas as rotas da API num formato padrão que os programas de desenvolvedor entendem sozinhos (chamado OpenAPI). Não é para ler — é para o seu desenvolvedor importar e ter tudo pronto para testar, sem digitar rota nenhuma.

Baixar: use o botão Baixar arquivo de integração no menu ao lado (sai o arquivo alfred-voice-api.json). Ou importe direto pelo endereço https://alfredvoice.com.br/api/openapi.json, que é sempre a versão mais nova.

No Postman

  1. Clique em Import (canto superior esquerdo).
  2. Arraste o arquivo alfred-voice-api.json — ou escolha Link e cole https://alfredvoice.com.br/api/openapi.json.
  3. Confirme em Import. Aparece a coleção Alfred Voice — API, com as rotas separadas em pastas: revenda, agentes, canais, conversas, voz, sms, ligações.
  4. Abra a coleção → aba Authorization → tipo Bearer Token → cole a sua chave av_.... Todas as rotas passam a usar a chave.
  5. Nas rotas que agem em nome de um cliente, marque o header X-Subconta e coloque o id da subconta. Sem ele, a chamada vale para a sua própria conta.
  6. Clique em Send. A resposta aparece embaixo — os formatos e os erros são os desta página.

No Insomnia

Create → Import → cole o endereço https://alfredvoice.com.br/api/openapi.json (ou escolha o arquivo baixado). A chave vai em Auth → Bearer Token, e o X-Subconta em Headers.

Gerar código de integração

Com o mesmo arquivo, ferramentas como o OpenAPI Generator (gratuito) geram o código de acesso à API na linguagem do seu sistema — PHP, Node, Python, Java, C# e outras. O desenvolvedor parte de um cliente pronto em vez de escrever cada chamada à mão.

Sempre atualizado

O arquivo é publicado junto com cada atualização da API, e o campo version mostra a data da versão. Se o seu desenvolvedor importou pelo endereço, basta reimportar para pegar as novidades. Toda rota citada no arquivo e nesta página é conferida automaticamente a cada atualização nossa: se está escrita aqui, existe de verdade.


3. Subcontas

Criar

curl -X POST https://alfredvoice.com.br/api/revenda/subcontas \
  -H "Authorization: Bearer av_..." \
  -H "Content-Type: application/json" \
  -d '{"nome":"Pizzaria do João","referencia":"crm-cliente-1042"}'
{"id":2,"nome":"Pizzaria do João","referencia":"crm-cliente-1042","ativa":true,"saldoCentavos":0,"disponivelCentavos":0,"criadaEm":"2026-09-24 15:05:37"}
CampoObrigatórioDescrição
nomesimNome do seu cliente (até 120 caracteres). Também vira o nome do primeiro agente dele.
referencianãoO id desse cliente no seu sistema (até 120). Única por revendedor: repetir dá 409 REFERENCIA_EM_USO.

Guarde o id devolvido: é ele que vai no header X-Subconta. A subconta nasce com um agente de ligação pronto, a mesma tarifa da sua conta, saldo zero e sem login no painel.

Listar e achar pela sua referência

curl "https://alfredvoice.com.br/api/revenda/subcontas?referencia=crm-cliente-1042" \
  -H "Authorization: Bearer av_..."
{"subcontas":[{"id":2,"nome":"Pizzaria do João","referencia":"crm-cliente-1042","ativa":true,"saldoCentavos":0,"disponivelCentavos":0,"criadaEm":"2026-09-24 15:05:37"}],"temMais":false,"proximoAntesDe":null}

Sem referencia, lista todas (50 por página, limite até 200). Para a próxima página, mande antesDe com o proximoAntesDe recebido.

Ver, editar, desativar

  • GET /revenda/subcontas/:id: uma subconta.
  • PUT /revenda/subcontas/:id com qualquer um de nome, referencia e ativa.
curl -X PUT https://alfredvoice.com.br/api/revenda/subcontas/2 \
  -H "Authorization: Bearer av_..." -H "Content-Type: application/json" \
  -d '{"ativa":false}'

Subconta desativada não faz nada novo: qualquer chamada com X-Subconta dela responde 403 SUBCONTA_INATIVA, ela não recebe transferência e o link de conexão dela deixa de valer. Campanha que já estava discando continua até o fim; se quiser interromper, pause ou pare a campanha antes de desativar (seção 9). Reativar é {"ativa":true}.

Resumo da sua conta

curl https://alfredvoice.com.br/api/revenda -H "Authorization: Bearer av_..."
{"saldoCentavos":50000,"disponivelCentavos":50000,"subcontas":{"total":1,"ativas":1,"maximo":100,"saldoCentavos":4000}}

subcontas.saldoCentavos é a soma do que está nas mãos dos seus clientes. O limite de subcontas (maximo) é combinado com a nossa equipe.


4. Saldo: transferir e devolver

Transferir para o cliente

curl -X POST https://alfredvoice.com.br/api/revenda/subcontas/2/transferir \
  -H "Authorization: Bearer av_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-778" \
  -d '{"valorCentavos":5000}'
{"id":1,"subcontaId":2,"sentido":"envio","valorCentavos":5000,"criadaEm":"2026-09-24 15:05:37","repetida":false,
 "subconta":{"id":2,"nome":"Pizzaria do João","referencia":"crm-cliente-1042","ativa":true,"saldoCentavos":5000,"disponivelCentavos":5000,"criadaEm":"2026-09-24 15:05:37"},
 "revendedor":{"saldoCentavos":45000}}

Devolver para você

POST /revenda/subcontas/:id/devolver com o mesmo corpo. O dinheiro volta do cliente para a sua conta.

{"id":2,"subcontaId":2,"sentido":"devolucao","valorCentavos":1000,"repetida":false,"subconta":{"...":"..."},"revendedor":{"saldoCentavos":46000}}

Regras que protegem o dinheiro

  • `valorCentavos` é número inteiro positivo (5000, nunca "5000" nem 50.00). Qualquer outra coisa: 400 VALOR_INVALIDO. Teto de R$ 100.000 por operação.
  • Só sai o que está disponível. Se não houver saldo, a resposta é 402 SALDO_INSUFICIENTE com disponivelCentavos, e nada se move. Ao devolver, o valor que está reservado por ligação em andamento não pode sair: disponivelCentavos já desconta essa reserva.
  • `Idempotency-Key` evita transferência dupla. Mande nele o id da operação no seu sistema (até 80 caracteres). Se a resposta se perder e você repetir a mesma chamada com a mesma chave, a transferência não acontece de novo: você recebe a original com "repetida": true e HTTP 200 (a primeira vez é 201). A mesma chave com outro valor ou outra subconta dá 409 IDEMPOTENCIA_CONFLITO. Recomendamos mandar sempre.
  • As duas pontas (a sua carteira e a do cliente) mudam juntas, numa operação só. Não existe meio-termo.

Extrato do cliente

curl "https://alfredvoice.com.br/api/revenda/subcontas/2/extrato?limite=50" -H "Authorization: Bearer av_..."
{"subconta":{"id":2,"nome":"Pizzaria do João","...":"..."},
 "extrato":[
  {"id":4,"quando":"2026-09-24 15:05:37","titulo":"Crédito devolvido","detalhe":"Devolvido ao revendedor","valorCentavos":-1000,"saldoDepoisCentavos":4000,"entrada":false},
  {"id":3,"quando":"2026-09-24 15:05:37","titulo":"Crédito recebido","detalhe":"Recebido do revendedor","valorCentavos":5000,"saldoDepoisCentavos":5000,"entrada":true}
 ],"temMais":false,"proximoAntesDe":null}

Cada ligação, torpedo, SMS e conversa cobrada aparece aqui, com o saldo depois de cada linha. Paginação igual à lista de subcontas (limite, antesDe).


5. Agir em nome do cliente (X-Subconta)

Mande o header em qualquer rota abaixo e ela passa a valer para aquele cliente: os agentes são dele, o WhatsApp é dele, o custo sai do saldo dele.

curl https://alfredvoice.com.br/api/saldo \
  -H "Authorization: Bearer av_..." \
  -H "X-Subconta: 2"
{"saldoCentavos":4000,"disponivelCentavos":4000}
ÁreaRotas
ContaGET /me, GET /saldo, GET /carteira (extrato)
Agentes de IAGET /agentes, POST /agentes, GET /agentes/:id, PUT /agentes/:id, DELETE /agentes/:id
WhatsAppPOST /canais/whatsapp/conectar, POST /canais/whatsapp/link-conexao, GET /canais/whatsapp/status, PUT /canais/whatsapp, POST /canais/whatsapp/desconectar
Balão do siteGET /agentes/:id/canal-site, PUT /agentes/:id/canal-site, DELETE /agentes/:id/canal-site
Torpedo de vozGET /voz/vozes, POST /voz/sintetizar, POST /voz/audios, GET /voz/audios, DELETE /voz/audios/:id, GET /voz/preco/:audioId, POST /voz/campanhas, GET /voz/campanhas, GET /voz/campanhas/:id, PUT /voz/campanhas/:id, POST /voz/campanhas/:id/pausar, POST /voz/campanhas/:id/retomar, POST /voz/campanhas/:id/parar
Ligação com agentePOST /ligacoes, GET /ligacoes, GET /ligacoes/:id, campanhas em lote (ver Integração por API)
SMSGET /sms, POST /sms/orcamento, POST /sms/enviar, GET /sms/relatorio, GET /sms/relatorio/:id, POST /sms/relatorio/:id/parar
ConversasGET /conversas, GET /conversas/:id, GET /conversas/:id/mensagens, POST /conversas/:id/modo, POST /conversas/:id/responder, POST /conversas/:id/status, POST /conversas/:id/vista

Regras:

  • O X-Subconta só funciona com a sua chave e só com subconta sua. Subconta de outro revendedor responde 404 SUBCONTA_NAO_ENCONTRADA, sem dizer se ela existe.
  • Dentro de uma subconta não dá para mexer na revenda (403 SO_REVENDEDOR), e o dinheiro não entra por recarga direta: POST /carteira/recarga responde 403 RECARGA_PELO_REVENDEDOR. O saldo do cliente entra só por transferência sua.
  • Sem o header, a chamada vale para a sua conta de revendedor.

6. Agentes de IA

Cada subconta nasce com um agente de ligação. Para atender no WhatsApp ou no site, crie um agente do canal certo — cada canal tem o seu.

curl -X POST https://alfredvoice.com.br/api/agentes \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"nome":"Atendente WhatsApp","canal":"whatsapp"}'
{"id":2}

canal: ligacoes (padrão), whatsapp ou site. Depois ensine o agente:

curl -X PUT https://alfredvoice.com.br/api/agentes/2 \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"promptRobo":"Você atende a Pizzaria do João. Seja cordial e objetivo.","contextoProduto":"Pizza grande: R$ 59\nPizza média: R$ 45\nEntrega grátis acima de R$ 80"}'
CampoPara que serve
promptRoboQuem o agente é e como ele fala.
contextoProdutoA base de conhecimento: cardápio, tabela de preço, perguntas frequentes. Pode ser longa (até cerca de 900 KB). Numa ligação de voz, o agente consulta a base na hora em vez de decorar tudo.
roteiroRoboPasso a passo da conversa (opcional, um passo por linha).
nomeComo o agente se apresenta.
smsTexto, smsGatilhoSMS depois da ligação (desligado, conectadas, todas).

Ver um agente:

curl https://alfredvoice.com.br/api/agentes/2 -H "Authorization: Bearer av_..." -H "X-Subconta: 2"
{"id":2,"nome":"Atendente WhatsApp","personaId":"yasmin","voz":"feminina","canal":"whatsapp","promptRobo":"","contextoProduto":"","roteiroRobo":"","smsHabilitado":1,"principal":0,"smsTexto":"","smsGatilho":"desligado"}
  • GET /agentes devolve {"smsHabilitado":1,"agentes":[{"id","nome","voz","canal","ativo"}]}.
  • DELETE /agentes/:id apaga. Não apaga o agente principal da conta (409 AGENTE_PRINCIPAL) nem um agente que está atendendo no WhatsApp ou no site (409 CANAL_LIGADO): troque o agente do canal ou desligue o canal antes.

7. WhatsApp do cliente

O número de WhatsApp do seu cliente responde texto, áudio e ligação de voz com o agente, tudo no mesmo número. Para conectar, o cliente precisa ler um QR Code com o celular. Você escolhe como entregar esse QR:

  • Opção A — no seu sistema: a API devolve o QR e você mostra na sua tela. É o caminho 100% com a sua marca.
  • Opção B — link pronto: a API devolve um link que você manda para o cliente (e-mail, WhatsApp, SMS). Ele abre, vê o QR e conecta. Você não desenha nada. A página não mostra a nossa marca, mas o endereço é do nosso domínio.

Nas duas opções, agenteId é um agente de canal whatsapp da subconta (senão 400 AGENTE_NAO_E_DE_WHATSAPP), e quando o número entra ou cai você recebe whatsapp.conectado / whatsapp.desconectado no aviso automático.

Opção A — mostrar o QR no seu sistema

curl -X POST https://alfredvoice.com.br/api/canais/whatsapp/conectar \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"agenteId":2}'
{"status":"aguardando_qr","qrcode":"data:image/png;base64,iVBORw0KGgo...","qrTexto":null}
  • qrcode é uma imagem (data URL) pronta para um <img src>. Quando vier null, use qrTexto: é o conteúdo do código, para você desenhar o QR com qualquer biblioteca de QR Code.
  • O código expira em segundos. Consulte o status a cada 3 a 5 segundos até conectar: enquanto ninguém lê, cada consulta traz um código novo.
  • Logo depois de conectar, o código pode levar alguns segundos para existir: status vem aguardando_qr com qrcode e qrTexto nulos. Não é erro — mostre "gerando o código" e siga consultando.
curl https://alfredvoice.com.br/api/canais/whatsapp/status -H "Authorization: Bearer av_..." -H "X-Subconta: 2"
{"status":"aguardando_qr","numero":null,"qrcode":"data:image/png;base64,iVBORw0KGgo...","qrTexto":null}
{"status":"conectado","numero":"5521999990000"}

status: nao_conectado, aguardando_qr (com qrcode/qrTexto novos), conectado ou desconectado.

O que dizer ao seu cliente na tela: *"Abra o WhatsApp no celular → Aparelhos conectados → Conectar um aparelho → aponte a câmera para o código."*

curl -X POST https://alfredvoice.com.br/api/canais/whatsapp/link-conexao \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"agenteId":2}'
{"url":"https://alfredvoice.com.br/conectar/bm5p5Sxb1nFtzNf1ZOBtIYgL15sPWoOPxknXykkFiI8","expiraEm":"2026-09-24 16:00:38"}
  • O link vale 30 minutos. Passou disso, a página avisa que expirou e você gera outro. Pode gerar quantos precisar.
  • A página mostra o nome do seu cliente, as instruções e o QR, troca o código sozinha e mostra Conectado! quando ele lê.
  • O link é a autorização: mande só para o seu cliente. Não guardamos o link, só uma impressão dele.
  • Se o número já estiver conectado: 409 JA_CONECTADO com o numero.

Trocar o agente, desconectar

  • PUT /canais/whatsapp com {"agenteId": 5}: outro agente de WhatsApp passa a atender o mesmo número.
  • POST /canais/whatsapp/desconectar: solta o número (o cliente também pode desconectar pelo celular).

Um aviso para o seu cliente: o número precisa estar só no WhatsApp Business do celular dele. Número ligado também a outra plataforma de API oficial pode recusar ligações de voz.


8. Balão no site do cliente

O agente de canal site atende num balão de conversa (texto e voz) no site do seu cliente. Você liga o balão pela API e entrega ao cliente uma linha para colar no site.

curl -X PUT https://alfredvoice.com.br/api/agentes/3/canal-site \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"dominios":["pizzariadojoao.com.br","www.pizzariadojoao.com.br"],"cor":"#E53935","nomeExibido":"Pizzaria do João","saudacao":"Oi! Quer ver o cardápio?"}'
{"canal":{"id":1,"ativo":1,"chavePublica":"pk_de7184a4b98e575f0a30652ca86d390b","dominios":["pizzariadojoao.com.br"],"cor":"#E53935","nomeExibido":"Pizzaria do João","saudacao":"Oi! Quer ver o cardápio?","vozAtiva":1,"criado_em":"2026-09-24 15:30:38"}}

A linha que o cliente cola antes do </body> do site (com a chavePublica da resposta):

<script src="https://alfredvoice.com.br/widget.js" data-chave="pk_de7184a4b98e575f0a30652ca86d390b" async></script>
CampoDescrição
dominiosOs endereços do site, sem https:// e sem caminho (pizzariadojoao.com.br). Até 20. O balão só abre nesses domínios: colado em outro site, ele não responde. Formato errado: 400 DOMINIOS_INVALIDOS.
corCor do balão, #RRGGBB. Errada: 400 COR_INVALIDA.
nomeExibidoNome no topo do balão (até 40).
saudacaoPrimeira mensagem (até 200).
vozAtiva1/0: se o visitante pode falar com o agente por voz.
gerarChavetrue troca a chavePublica (o código antigo para de funcionar — o cliente precisa colar o novo).
  • GET /agentes/:id/canal-site devolve a configuração atual ({"canal": null} se ainda não foi ligado).
  • DELETE /agentes/:id/canal-site desliga o balão.
  • O agente precisa ser de canal site: senão 400 AGENTE_NAO_E_DE_SITE.
  • A chavePublica fica visível no site do cliente de propósito: ela só abre o balão, nos domínios cadastrados. Não é a sua chave de API.

As conversas do balão aparecem em GET /conversas?canal=site (seção 12).


9. Torpedo de voz

Uma gravação que toca para uma lista inteira. Só é cobrado o que conecta; quem não atende não custa nada.

1) O áudio: gerar por texto ou enviar o seu

Gerar a gravação a partir de texto (a geração tem custo, debitado na hora):

curl https://alfredvoice.com.br/api/voz/vozes
{"vozes":[{"id":"ana","nome":"Ana","genero":"feminina","descricao":"Calorosa e próxima"},{"id":"rafael","nome":"Rafael","genero":"masculina","descricao":"Firme e direto"}]}
curl -X POST https://alfredvoice.com.br/api/voz/sintetizar \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"texto":"Olá! A Pizzaria do João está com promoção hoje: pizza grande por 49 reais.","vozId":"ana","nome":"Promo sexta"}'

Ou enviar um arquivo seu. O corpo é o arquivo cru, não JSON:

curl -X POST "https://alfredvoice.com.br/api/voz/audios?nome=Promo%20sexta" \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" \
  -H "Content-Type: audio/mpeg" --data-binary @promo.mp3

Os dois devolvem o áudio (201):

{"id":1,"nome":"Promo sexta","token":"va_...","duracaoSeg":18,"bytes":150000,"criadoEm":"2026-09-24 15:31:11"}

Aceitamos até 25 MB e até 5 minutos; o arquivo é convertido para MP3 no servidor. Texto para gerar: até 4.000 caracteres. GET /voz/audios lista; DELETE /voz/audios/:id apaga.

Quanto custa cada ligação que conectar com esse áudio:

curl https://alfredvoice.com.br/api/voz/preco/1 -H "Authorization: Bearer av_..." -H "X-Subconta: 2"
{"duracaoSeg":18,"custoPorLigacaoCentavos":20,"custoProvavelCentavos":20,"risco":false,"margemSeg":5,"duracaoSeguraSeg":24}

2) A campanha

curl -X POST https://alfredvoice.com.br/api/voz/campanhas \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"nome":"Promo sexta","audioId":1,"numeros":["21999990001","+55 21 98888-0002","abc"],"quando":"2026-09-26T18:00:00Z","smsGatilho":"conectadas","smsTexto":"Peça pelo link: exemplo.com"}'
{"id":1,"clienteId":2,"nome":"Promo sexta","audioId":1,"status":"agendada","motivo":null,"quando":"2026-09-26 18:00:00","smsTexto":"Peça pelo link: exemplo.com","smsGatilho":"conectadas","iniciadaEm":null,"concluidaEm":null,"criadaEm":"2026-09-24 15:31:11","total":2,"fila":2,"conectaram":0,"naoConectaram":0,"gastoCentavos":0,"invalidos":["abc"]}
CampoDescrição
audioIdO áudio do passo 1.
numerosLista (array) ou texto separado por linha, vírgula ou ponto e vírgula. Até 100.000. Os inválidos voltam em invalidos, e o resto segue.
quandoData e hora ISO (UTC). Vazio ou "agora" dispara em seguida.
nomeNome da campanha (opcional).
smsGatilho / smsTextoSMS depois da ligação: desligado, conectadas ou todas; texto até 160 caracteres.

status da campanha: agendada, disparando, pausada (com motivo), concluida, cancelada ou perdida.

3) Controlar

  • POST /voz/campanhas/:id/pausar: segura a fila (o que já foi chamado fica).
  • POST /voz/campanhas/:id/retomar: continua de onde parou, sem ligar de novo para quem já foi chamado.
  • POST /voz/campanhas/:id/parar: encerra; o resto da fila não é chamado.
  • PUT /voz/campanhas/:id (mesmo corpo da criação): edita, só enquanto ainda não começou (depois disso, 409 JA_COMECOU).
  • GET /voz/campanhas / GET /voz/campanhas/:id: andamento, com total, fila, conectaram, naoConectaram, gastoCentavos e motivo.

Sem saldo para continuar, a campanha pausa sozinha com o motivo; transfira saldo e chame retomar.

O torpedo dispara na hora que você marcar: escolha horário comercial. Campanha que não conseguiu começar até 2 horas depois da hora marcada vira perdida e não dispara mais (para não ligar para ninguém fora de hora).

Cada número que termina gera torpedo.finalizado; a lista inteira gera torpedo.campanha_concluida (seção 13).


10. Ligação com agente de IA

É o agente conversando com a pessoa, não uma gravação. Funciona igual à Integração por API (seções 3, 4 e 6), com X-Subconta no header:

curl -X POST https://alfredvoice.com.br/api/ligacoes \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"numero":"21999990001","agenteId":1,"referencia":"lead-8842"}'

Sem agenteId, atende o agente principal da subconta. O resultado chega em ligacao.finalizada. Ligações com agente saem entre 8h e 20h (horário de Brasília).


11. SMS

curl -X POST https://alfredvoice.com.br/api/sms/orcamento \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"texto":"Seu pedido saiu!","destinos":["21999990001","x"]}'
{"quantidade":1,"invalidos":1,"custoCentavos":7,"saldoCentavos":0}

POST /sms/enviar com o mesmo corpo envia de verdade. Até 160 caracteres por mensagem e até 200.000 números por envio (maxDestinos); fora isso, o limite é o seu saldo. GET /sms mostra se o SMS está liberado, o saldo, o preço e o máximo de números por envio:

{"liberado":1,"saldoCentavos":4000,"custoPorCemCentavos":650,"maxDestinos":200000,"maxTexto":160}

Até 500 números, nada muda: a resposta só volta depois do envio, já com o resultado (200, com enviados e falharam). Acima de 500 números, o envio inteiro é cobrado na hora e a resposta volta logo, com 202, enquanto os SMS saem em segundo plano:

{"ok":true,"envioId":"a1b2c3","total":5000,"emSegundoPlano":true,"cobradoCentavos":32500,"saldoCentavos":7500,"invalidos":["x"]}

Acompanhe pelo relatório (GET /sms/relatorio/{id}): status fica enviando até terminar e pendentes diz quantos números ainda estão na fila. Quando termina, tudo que não saiu volta sozinho ao saldo e custoCentavos mostra o valor final: o preço por SMS do momento do envio vezes os que saíram. Mudança de preço durante o envio não altera a conta desse envio.

Para interromper, POST /sms/relatorio/{id}/parar. O que ainda não saiu não é mais enviado e volta ao saldo na hora:

{"ok":true,"status":"parado","estornadoCentavos":20800}

Se algum número estava preso no canal exatamente na hora, a resposta vem com "status":"parando" e estornadoCentavos: 0: o envio já não manda mais nada e o estorno entra sozinho em seguida. Acompanhe pelo relatório até o status virar parado.

Envio de outra conta ou inexistente responde 404 {"error":"NAO_ENCONTRADO"}; envio que já terminou (ou já foi parado) responde 409 {"error":"JA_TERMINOU"}. Se a nossa plataforma reiniciar no meio, o envio continua sozinho de onde parou. Um número que estava saindo exatamente na hora do reinício não é mandado de novo (para não chegar duas vezes) e o valor dele volta ao saldo.

Sem saldo, o envio não sai:

{"error":"SEM_SALDO","custoCentavos":7,"saldoCentavos":0}

Relatório de SMS

GET /sms/relatorio lista os envios da conta (ou da subconta, com X-Subconta), do mais recente para o mais antigo, até 500:

[{"id":"a1b2c3","criadoEm":"2026-10-02 14:30:00","texto":"Seu pedido saiu!","total":2,"enviados":1,"falharam":1,"invalidos":0,"custoCentavos":7,"origem":"api","legado":false,"status":"concluido","pendentes":0}]
  • total é quantos números foram para envio; enviados e falharam são o resultado; invalidos são os números descartados antes de enviar.
  • custoCentavos é o que foi cobrado, já descontado o estorno dos que falharam.
  • origem é api (chave) ou painel.
  • status é enviando (ainda saindo, em segundo plano), parando (você parou e o estorno ainda vai entrar), parado (você parou, conta fechada) ou concluido. pendentes é quantos números ainda estão na fila (0 quando terminou).
  • Enquanto está enviando, custoCentavos é o valor cobrado na hora; o estorno do que não saiu entra quando o envio termina ou é parado.
  • entrega mostra o aviso de entrega recebido, só para consulta (não muda cobrança nem estorno): entregues, naoEntregues (não entregue, rejeitado ou expirado), aguardando (já saiu, ainda sem aviso) e semAviso (enviados antes do aviso existir, ou sem identificador). Sem aviso ainda não quer dizer que falhou.
  • Envios feitos antes do relatório aparecem com legado: true: só têm data, quantidade (pode vir null) e custo; texto, enviados, falharam, invalidos e origem vêm null (status vem concluido).

GET /sms/relatorio/{id} devolve o mesmo envio com a lista dos números, em páginas de até 1.000 (?limite= até 5.000). numerosTotal é quantos números já foram processados e proximo é o valor para pedir a página seguinte (?apos=<proximo>); null quando acabou:

{"id":"a1b2c3","criadoEm":"2026-10-02 14:30:00","texto":"Seu pedido saiu!","total":2,"enviados":1,"falharam":1,"invalidos":0,"custoCentavos":7,"origem":"api","legado":false,"status":"concluido","pendentes":0,
 "numeros":[{"numero":"5521999990001","status":"enviado","motivo":null},{"numero":"5521999990002","status":"falhou","motivo":"FALHOU"}],"numerosTotal":2,"proximo":null}

Em cada número, entrega é o último aviso de entrega (DELIVRD entregue, UNDELIV não entregue, REJECTD rejeitado, EXPIRED expirado; null se ainda não chegou aviso), entregaEm é quando o aviso chegou e temAviso diz se esse número pode receber aviso de entrega (false para envios antigos ou sem identificador).

O id é um texto (o mesmo da lista). Envio de outra conta, inexistente ou legado responde 404 {"error":"NAO_ENCONTRADO"}. Durante um envio em segundo plano, numeros traz só os que já foram processados; os que estão na fila aparecem em pendentes. Um número com motivo INTERROMPIDO estava saindo quando a plataforma reiniciou: não foi mandado de novo e o valor voltou ao saldo.


12. Conversas (WhatsApp e site)

Tudo o que o agente conversou, para você mostrar no seu sistema e deixar um atendente humano assumir quando precisar.

curl "https://alfredvoice.com.br/api/conversas?canal=whatsapp&limite=50" -H "Authorization: Bearer av_..." -H "X-Subconta: 2"
{"conversas":[{"id":1,"canal":"whatsapp","agenteId":2,"agenteNome":"Atendente WhatsApp","origemDominio":null,"modo":"agente","status":"aberta","contatoNome":"Maria","contatoNumero":"5521988887777","iniciadaEm":"2026-09-24 15:31:11","ultimaEm":"2026-09-24 15:31:11","vistaEm":null,"mensagens":2,"vozSeg":0,"custoCentavos":0,"ultimaMensagem":"Oi, Maria! A pizza grande sai por R$ 59.","naoLidas":1}]}

Filtros: canal (whatsapp ou site), modo (agente ou humano), busca (nome ou telefone), limite e antes (id, para a próxima página).

curl https://alfredvoice.com.br/api/conversas/1/mensagens -H "Authorization: Bearer av_..." -H "X-Subconta: 2"
{"mensagens":[{"id":1,"quem":"visitante","tipo":"texto","texto":"Oi, qual o preço da pizza grande?","criadoEm":"2026-09-24 15:31:11"},{"id":2,"quem":"agente","tipo":"texto","texto":"Oi, Maria! A pizza grande sai por R$ 59.","criadoEm":"2026-09-24 15:31:11"}],"temMais":false}

quem: visitante (a pessoa) ou agente (o agente ou o atendente).

Atendente humano assume e responde:

curl -X POST https://alfredvoice.com.br/api/conversas/1/modo \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"modo":"humano"}'
{"modo":"humano"}
curl -X POST https://alfredvoice.com.br/api/conversas/1/responder \
  -H "Authorization: Bearer av_..." -H "X-Subconta: 2" -H "Content-Type: application/json" \
  -d '{"texto":"Oi, Maria! Aqui é o João. Posso te ajudar?"}'
  • No modo humano o agente para de responder; {"modo":"agente"} devolve a conversa para ele.
  • responder só funciona no modo humano (senão 409 AGENTE_NO_COMANDO) e com o WhatsApp conectado (senão 503 NUMERO_DESCONECTADO). Texto de 1 a 2.000 caracteres.
  • POST /conversas/:id/vista marca como lida; POST /conversas/:id/status com {"status":"concluida"} arquiva e {"status":"aberta"} reabre.

13. Avisos automáticos

Os avisos de todas as subcontas chegam na URL cadastrada na sua conta, no envelope de sempre, com um campo a mais: subconta.

{
  "evento": "torpedo.finalizado",
  "entrega_id": "8f14e45f-ceea-467a-9c2e-6b1d2b8a3f41",
  "enviado_em": "2026-09-26T18:02:11.204Z",
  "subconta": { "id": 2, "referencia": "crm-cliente-1042" },
  "dados": {
    "campanha_id": 51, "numero": "5521999990001", "codigo": "17288241",
    "status": "conectou", "resultado": "Atendido", "duracao_seg": 18, "custo_centavos": 20
  }
}

Use subconta.referencia para achar o cliente no seu banco. Assinatura, headers, repetição e reenvio funcionam igual à Integração por API (seção 5). Responda 2xx em até 8 segundos; se não, repetimos.

EventoQuando dispara`dados`
torpedo.finalizadoUm número do torpedo terminou (uma vez por número).campanha_id, numero, codigo, status (conectou/nao_conectou), resultado, duracao_seg, custo_centavos
torpedo.campanha_concluidaA lista inteira do torpedo terminou.campanha_id, nome, total, conectaram, nao_conectaram, gasto_centavos
whatsapp.conectadoO número do cliente entrou no ar.numero, status
whatsapp.desconectadoO número caiu ou foi desconectado.numero, status
ligacao.finalizadaUma ligação com agente terminou.ver Integração por API
campanha.concluidaUma lista de ligações com agente terminou.idem
sms.enviadoSaiu o SMS de pós-ligação.idem
conversa.contatoO agente colheu nome, telefone ou e-mail numa conversa.idem
reuniao.marcadaO agente marcou uma reunião.idem

torpedo.finalizado com resultado: "sem retorno" significa que a operadora não confirmou o desfecho em até 60 minutos: fica como não conectado e não é cobrado.


14. Consumo: quanto cada cliente gastou

curl "https://alfredvoice.com.br/api/revenda/consumo?de=2026-09-01&ate=2026-09-30" -H "Authorization: Bearer av_..."
{"de":"2026-09-01","ate":"2026-09-30","gastoTotalCentavos":470,
 "subcontas":[{"subcontaId":2,"nome":"Pizzaria do João","referencia":"crm-cliente-1042",
   "centavos":{"ligacaoAgente":120,"torpedo":300,"sinteseDeVoz":0,"sms":50,"conversas":0,"outros":0,"recebido":5000,"devolvido":1000,"estornos":0},
   "gastoTotalCentavos":470}]}
  • de / ate no formato AAAA-MM-DD, em UTC, com ate incluso. Sem eles: os últimos 30 dias. Data em outro formato: 400 PERIODO_INVALIDO.
  • subcontaId=2 filtra um cliente só.
  • gastoTotalCentavos é o consumo: ligação com agente, torpedo, geração de voz, SMS e conversas, menos estornos. recebido e devolvido são as suas transferências e não entram no gasto.
  • É o valor que saiu do nosso lado. Quanto você cobra do seu cliente é com você.

15. Erros

Todo erro vem como {"error":"CODIGO"}, às vezes com campos que ajudam (disponivelCentavos, invalidos, mensagem). Nunca devolvemos detalhe interno.

Gerais

HTTPCódigoSignificadoO que fazer
401TOKEN_REQUERIDOFaltou o header Authorization.Mande Bearer av_....
401NAO_AUTORIZADOChave inexistente, revogada ou de conta desativada.Confira a chave no painel.
403SO_SESSAORota só do painel (ex.: criar chave, cadastrar aviso).Faça pelo painel.
404NAO_ENCONTRADORecurso não existe ou não é dessa conta.Confira o id e o X-Subconta.
429LIMITEPassou do teto de requisições da chave.Espere o Retry-After (segundos).
500ERRO_INTERNODeu errado do nosso lado.Tente de novo; se insistir, fale com o suporte com o horário.

Revenda e saldo

HTTPCódigoSignificado
400FALTA_NOMESubconta sem nome.
400VALOR_INVALIDOvalorCentavos não é inteiro positivo (ou passou de R$ 100.000).
400PERIODO_INVALIDOde/ate fora do formato AAAA-MM-DD ou invertidos.
402SALDO_INSUFICIENTENão há saldo disponível para mover. Vem com disponivelCentavos.
403SEM_REVENDAA conta não tem revenda liberada, ou a chave não é de revendedor.
403SO_REVENDEDORRota de revenda chamada com X-Subconta.
403SUBCONTA_INATIVAA subconta está desativada.
403RECARGA_PELO_REVENDEDORRecarga direta dentro de uma subconta: o saldo entra só por transferência.
404SUBCONTA_NAO_ENCONTRADANão existe, ou não é sua.
409REFERENCIA_EM_USOJá existe subconta sua com essa referencia.
409LIMITE_SUBCONTASVocê chegou ao máximo combinado. Fale com a gente.
409IDEMPOTENCIA_CONFLITOA mesma Idempotency-Key foi usada para outra operação.

Agentes e balão do site

HTTPCódigoSignificado
400FALTA_NOMEAgente sem nome.
400CANAL_INVALIDOcanal diferente de ligacoes, whatsapp ou site.
400GATILHO_INVALIDOsmsGatilho diferente de desligado, conectadas ou todas.
400CORPO_INVALIDOCorpo da requisição malformado.
413TEXTO_GRANDE_DEMAISBase de conhecimento acima do limite.
409AGENTE_PRINCIPALApagar o agente principal da conta.
409CANAL_LIGADOApagar um agente que está atendendo no WhatsApp ou no site.
400AGENTE_NAO_E_DE_SITELigar o balão num agente que não é de canal site.
400DOMINIOS_INVALIDOSDomínio com https://, caminho, porta ou mais de 20.
400COR_INVALIDACor fora do formato #RRGGBB.

WhatsApp

HTTPCódigoSignificadoO que fazer
400AGENTE_NAO_E_DE_WHATSAPPO agenteId não é de canal whatsapp.Crie ou use um agente whatsapp.
409JA_CONECTADOO número já está conectado (vem com numero).Nada a fazer; para trocar, desconecte antes.
404LINK_INVALIDOLink de conexão que não existe (ou de subconta desativada).Gere outro.
410LINK_EXPIRADOPassaram os 30 minutos do link.Gere outro.
502MOTOR_INDISPONIVELO serviço de WhatsApp não respondeu agora.Tente de novo em alguns segundos.
503INDISPONIVELConexão de WhatsApp temporariamente fora do ar.Tente de novo em alguns minutos.

Torpedo de voz

HTTPCódigoSignificado
400SEM_AUDIO / AUDIO_NAO_ENCONTRADOFaltou o audioId, ou o áudio não existe mais.
400SEM_NUMERONenhum número válido na lista (vem com invalidos).
400NUMEROS_DEMAISA lista passou de 100.000 números.
400HORA_INVALIDAquando que não é data e hora.
409JA_COMECOUEditar campanha que já começou (dá para pausar ou parar).
404NAO_ENCONTRADACampanha não existe ou não é dessa conta.
400SEM_ARQUIVO / GRANDE_DEMAIS / NAO_E_AUDIOEnvio de áudio vazio, acima de 25 MB ou que não é áudio.
400CURTO_DEMAIS / LONGO_DEMAISÁudio com menos de 1 segundo ou mais de 5 minutos.
400TEXTO_VAZIO / TEXTO_LONGO / VOZ_DESCONHECIDAGeração de áudio sem texto, com texto acima do limite ou com vozId fora da lista.
402SALDO_INSUFICIENTESem saldo para gerar o áudio por texto.
503SINTESE_INDISPONIVELA geração de voz não respondeu agora; tente de novo em instantes.

Os erros de áudio e de campanha vêm com mensagem em português, pronta para mostrar ao usuário.

SMS

HTTPCódigoSignificado
400TEXTO_VAZIOMensagem sem texto.
400SEM_DESTINONenhum número válido (vem com invalidos).
402SEM_SALDOSaldo não cobre o envio inteiro (vem com custoCentavos e saldoCentavos). Nada é cobrado.
404NAO_ENCONTRADOParar: envio inexistente ou de outra conta.
400DESTINOS_DEMAISMais de 200.000 números num envio (vem com limite).
409JA_TERMINOUParar: o envio já terminou ou já foi parado.
403SMS_NAO_LIBERADOSMS não está liberado nesta conta. Fale com a gente.

Conversas

HTTPCódigoSignificado
400MODO_INVALIDOmodo diferente de agente ou humano.
400MENSAGEM_INVALIDAResposta vazia ou com mais de 2.000 caracteres.
400STATUS_INVALIDOstatus diferente de aberta ou concluida.
409AGENTE_NO_COMANDOResponder sem antes passar para o modo humano.
503NUMERO_DESCONECTADOO WhatsApp da subconta está desconectado.

Ligação com agente

HTTPCódigoSignificado
400NUMERO_INVALIDOO telefone não é um número brasileiro válido.
403SO_DEMOA conta ainda não está liberada para ligação real.
404AGENTE_NAO_ENCONTRADOO agenteId não é dessa conta.

16. Limites

LimiteValor
Requisições por chave120 por minuto, somando todas as subcontas que usam aquela chave. Ao estourar: 429 LIMITE + Retry-After. Com muitos clientes, distribua em até 5 chaves.
Consultas ao link de conexão60 por minuto por IP (a página consulta a cada 4 segundos).
SubcontasO máximo combinado com a gente (veja maximo em GET /revenda).
TransferênciaAté R$ 100.000 por operação.
Base de conhecimento do agenteCerca de 900 KB de texto.
Torpedo100.000 números por campanha; áudio até 25 MB e 5 minutos; texto para gerar voz até 4.000 caracteres.
SMS160 caracteres por mensagem; até 200.000 números por envio (e o saldo). Acima de 500 números, o envio sai em segundo plano.
Orçamento de SMS (POST /sms/orcamento)600 por hora por conta. Corpo até 10 MB só em conta com SMS liberado (as outras: 256 KB).
Resposta de atendente na conversa2.000 caracteres.
Link de conexão do WhatsApp30 minutos.
Resposta do seu servidor ao aviso8 segundos.

17. Roteiro de teste de ponta a ponta

Faça uma vez com o seu próprio celular antes de pôr um cliente real:

  1. GET /revenda: confirma a chave e o saldo.
  2. POST /revenda/subcontas com {"nome":"Teste","referencia":"teste-1"} e anote o id.
  3. POST /revenda/subcontas/:id/transferir com {"valorCentavos":500} e uma Idempotency-Key. Repita a mesma chamada e confira "repetida": true.
  4. WhatsApp: com X-Subconta, crie um agente whatsapp, ponha um contextoProduto curto e gere o link em /canais/whatsapp/link-conexao. Abra o link, leia o QR com um WhatsApp de teste e mande uma mensagem para esse número: o agente responde, e chega whatsapp.conectado na sua URL.
  5. Site: crie um agente site, ligue o balão com o domínio de uma página sua, cole a linha <script> e converse.
  6. Torpedo: gere um áudio em /voz/sintetizar e crie uma campanha com o seu número. Atenda: chega torpedo.finalizado e depois torpedo.campanha_concluida, com a subconta.
  7. GET /revenda/consumo: o torpedo e a geração de voz aparecem no gasto da subconta.
  8. POST /revenda/subcontas/:id/devolver com o que sobrou, depois PUT com {"ativa":false}.

Fechou o roteiro, a integração está pronta.