Saltar para o conteúdo

Fazer chamadas a partir de um workflow do n8n

September 2, 2026 · 7 min de leitura

É possível ligar a um cliente a partir do n8n sem escrever uma única linha de código: adicione ao workflow um nó HTTP Request, aponte-o para POST https://volai.cz/v1/calls com o cabeçalho Authorization: Bearer vk_... e um corpo com {to, agentId} - e o seu agente de voz marca o número exatamente quando o workflow o exigir. Segue-se a configuração completa: como passar os dados do workflow para o prompt do agente, como devolver o resultado da chamada ao n8n e como ligar sem agente, unindo diretamente dois números.

O que vai precisar

  • Uma instância do n8n - na cloud ou auto-alojada, qualquer versão recente.
  • Uma conta volai e uma chave de API do portal (Definições -> API e MCP), no formato vk_.... Guarde-a no n8n como credencial Header Auth (cabeçalho Authorization, valor Bearer vk_...), para não ter de copiar a chave para cada nó.
  • Um número próprio com um agente de voz associado - crie-o no portal ou através de /docs/agent. Ainda não tem agente? Pode ligar na mesma, unindo diretamente dois números (a variante com from abaixo).

1Adicionar um nó HTTP Request

Método POST, URL https://volai.cz/v1/calls, autenticação através da credencial guardada, Body Content Type JSON. O corpo precisa de to (o número do cliente) e agentId (o id do agente no portal) - ambos obrigatórios - e de exatamente UM de agentId/from/systemPrompt, nunca mais do que um.

json
{
  "to": "={{ $json.phone }}",
  "agentId": "ag_kx91fa2b",
  "variables": {
    "customer_name": "={{ $json.name }}",
    "order_number": "={{ $json.order }}"
  },
  "ringingTimeoutSecs": 30
}

Os valores escritos como ={{...}} são expressões do n8n - $json lê campos do nó anterior do workflow (por exemplo, um webhook de «nova encomenda» ou uma linha de uma folha de cálculo).

2Passar os dados do workflow para o prompt do agente

variables é um objeto de texto para texto que o agente recebe como variáveis dinâmicas - no prompt de sistema, refira-se a elas como {{customer_name}}. Limites: no máximo 20 chaves, chaves até 64 carateres, valores até 512 carateres. Os nomes attempt_id, caller_number e called_number são reservados - a volai preenche-os por si, e os valores equivalentes vindos do workflow seriam descartados.

ringingTimeoutSecs (de 5 a 60 segundos, por omissão 25) define durante quanto tempo o telefone toca antes de uma chamada sem resposta terminar com endReason: "no_answer". Um tempo limite maior aumenta a probabilidade de o cliente atender, mas também ocupa mais tempo uma linha de saída.

3Ler a resposta e, se quiser, aguardar o resultado

A resposta de sucesso chega logo, mas a chamada acabou de começar - status é initiated, não um estado final:

json
{
  "id": "c_9d4e2b7f",
  "status": "initiated"
}

Prefere esperar pelo resultado na mesma execução do workflow, em vez de um webhook separado? Adicione um segundo nó logo a seguir ao HTTP Request, que chame GET /v1/calls/{id} com o parâmetro waitSecs (de 0 a 45 segundos) - o servidor responde quando a chamada termina ou quando o tempo limite é atingido, o que acontecer primeiro:

bash
curl "https://volai.cz/v1/calls/c_9d4e2b7f?waitSecs=30" \
  -H "Authorization: Bearer vk_YOUR_KEY"

Receber o resultado: um webhook para o n8n

Num workflow de produção costuma ser mais prático não esperar em linha e receber o resultado em separado: adicione um nó Webhook no n8n (um workflow novo serve), copie o respetivo Production URL e registe-o uma só vez na volai:

bash
curl -X PUT https://volai.cz/v1/webhook \
  -H "Authorization: Bearer vk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-instance.app.n8n.cloud/webhook/volai-calls",
    "events": ["call.completed", "call.failed", "call.no_answer"]
  }'

A resposta inclui um secret (no formato whsec_...) - guarde-o, pois vai precisar dele para verificar a assinatura de cada pedido recebido. A volai envia um cabeçalho Volai-Signature no formato t=<unix>,v1=<hex> - o código completo de verificação em TypeScript e Python encontra-se em /docs/webhooky. Não pode ser transposto sem alterações para um nó Code do n8n: o HMAC é calculado sobre o corpo BRUTO do pedido, pelo que tem de ativar a opção Raw Body no nó Webhook (sem ela, o n8n entrega JSON já interpretado e a assinatura nunca coincide) e importar crypto no nó Code com require, não com import. Não processe o corpo antes de verificar a assinatura.

O que chega quando a chamada termina:

json
{
  "event": "call.completed",
  "ts": 1756111640000,
  "data": {
    "id": "c_9d4e2b7f",
    "direction": "out",
    "from": "+420601234567",
    "to": "+420777123456",
    "status": "completed",
    "durationSecs": 90,
    "priceHal": 513,
    "answeredBy": "human",
    "endReason": "completed",
    "transcript": [
      { "role": "agent", "message": "Boa tarde, ligo a propósito da encomenda A-42." },
      { "role": "caller", "message": "Sim, já sei, obrigado pelo lembrete." }
    ],
    "summary": "O cliente confirmou a receção da encomenda A-42.",
    "data": {
      "order_confirmed": true
    }
  }
}

A chave data aninhada dentro de data é opcional e contém exatamente os campos que configurou no agente em dataFields - o exemplo acima (order_confirmed) é apenas ilustrativo, os seus serão outros. Um nó seguinte do n8n pode então ramificar com base nesses campos, por exemplo para atualizar um registo no CRM ou reagendar a chamada.

Como ligar sem agente?

Quando não precisa de um agente de voz, apenas de uma ligação direta entre dois números (por exemplo, um comercial e um cliente), envie from em vez de agentId:

json
{
  "to": "+420777123456",
  "from": "+420601234567"
}

A volai liga primeiro para from e, quando alguém atende, marca to. Os dois troços são faturados em separado a 0.92 CZK por minuto (sem suplemento do agente). from é o número onde ATENDE - normalmente o seu telemóvel - e pode ser qualquer número checo ou eslovaco, não tem de pertencer à sua conta volai. O requisito real é outro: a conta precisa de pelo menos um número volai próprio, porque é por ele que a chamada é faturada e é ele que os dois lados veem no ecrã (sem isso, a volai devolve bridge_needs_number). Apenas não coloque em from um número volai encaminhado para um agente ou para SIP - a rede ligaria esse primeiro troço ao agente em vez de a si, e a chamada nunca tocaria no seu telefone.

Quanto custa uma chamada destas?

Uma chamada efetuada através de um agente é faturada como a soma de duas tarifas: o minuto de chamada efetuada (0.92 CZK) mais o suplemento do agente POR CIMA (2.50 CZK), ambos segundo a tabela de preços de 2 de setembro de 2026. Uma chamada de 90 segundos sai por 5.13 CZK:

ItemTarifaChamada de 90 s
Minuto de chamada efetuada0.92 CZK/min1.38 CZK
Suplemento do agente2.50 CZK/min3.75 CZK
Total5.13 CZK

A faturação é feita ao segundo, não por minuto inteiro - uma chamada mais curta custa proporcionalmente menos. A tabela de preços completa (números, agente, SMS) está em /cenik.

Repetir em segurança (Idempotency-Key)

O n8n pode repetir automaticamente um nó em caso de falha (Retry On Fail) - sem salvaguarda, isso significaria duas chamadas telefónicas reais ao mesmo cliente. Adicione um cabeçalho Idempotency-Key com um valor estável durante uma execução do workflow (o n8n expõe-no como {{ $execution.id }}, ou use o id da sua encomenda) - com a mesma chave, nas 24 horas seguintes recebe a resposta da primeira tentativa e a chamada não é efetuada duas vezes:

bash
curl -X POST https://volai.cz/v1/calls \
  -H "Authorization: Bearer vk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: reminder-order-A-42" \
  -d '{"to": "+420777123456", "agentId": "ag_kx91fa2b"}'

O que fazer quando a API devolve um erro?

Esta tabela cobre as variantes agentId e from - os estados específicos de uma chamada de teste sem número próprio ( systemPrompt) ficam propositadamente de fora, por ser outro fluxo.

EstadoCódigoSignificado
400invalid_numberO campo to não é um número de telefone válido.
400validationFalta agentId/from, ou ambos estão definidos; ou variables excede os limites, ou ringingTimeoutSecs está fora do intervalo de 5 a 60.
400on_dncO número está na sua lista de números a não contactar (/v1/dnc).
400destination_auto_blockedEste destino foi bloqueado automaticamente durante 30 dias após falhas repetidas.
400cannot_call_own_numberProteção contra ciclos - não pode ligar para o seu próprio número volai.
404agent_not_foundagentId não existe ou não pertence à sua conta.
404agent_no_numberO agente não tem nenhum número de telefone atribuído.
404bridge_needs_numberPara a variante from: a conta precisa de pelo menos um número volai.
409destination_busyJá tem outra chamada em curso para esse mesmo número.
402insufficient_creditO seu saldo não cobre o mínimo necessário para iniciar uma chamada.
503capacity_busyTodas as linhas de saída estão ocupadas neste momento, tente de novo dentro de um minuto.

O limite geral da API

Além da tabela acima, aplica-se um limite em toda a API: no máximo 60 pedidos por minuto por chave de API (HTTP 429, rate_limited). Tenha-o em conta num workflow que marque dezenas de números seguidos - o mesmo limite aplica-se a POST /v1/messages e a todos os outros endpoints sob a mesma chave.

Próximos passos

Um resumo completo do que pode fazer a partir do n8n (SMS, números, lista de números a não contactar) encontra-se no guia de integração com o n8n. A referência REST completa está em /docs/api, e a lista completa de eventos de webhook com verificação de assinatura em /docs/webhooky.

Experimente a volai - os primeiros 50 kr são nossos

Registe-se em um minuto e a sua conta já tem saldo inicial para chamadas e um número - os SMS funcionam depois do primeiro carregamento.

Experimentar gratuitamente