Sign inGet Started

Use dados do aplicativo em uma sequência de voz

Use voice.webhook quando seu aplicativo tiver dados de que a chamada precisa: o status de um pedido, uma equipe ou a confirmação de um agendamento. A etapa retorna esses dados em success, e uma etapa Branch posterior escolhe o caminho com base neles.

Defina a resposta

Defina config.output_schema como um schema de objeto para os dados retornados. A etapa tem duas saídas: success transporta dados nesse schema e failure trata problemas técnicos. Se a configuração for omitida, a saída é um objeto vazio.

A entrada contém um HTTPS url estático e um data de objeto opcional. Os dados aceitam um objeto literal, $literal ou um $expr de objeto inteiro. URLs dinâmicas, cabeçalhos definidos por você e credenciais não são aceitos.

Verifique as solicitações

O Bird assina cada solicitação, inclusive as continuações, com o segredo de callback do seu espaço de trabalho, usando cabeçalhos Standard Webhooks: webhook-id, webhook-timestamp e webhook-signature. A assinatura cobre o ID, o timestamp e o corpo exato. Nas 24 horas seguintes à troca de um segredo, webhook-signature traz uma entrada v1, para cada segredo ativo, então qualquer um dos dois segredos passa na verificação. As chamadas podem levar cerca de um minuto para começar a assinar com o novo segredo, então continue aceitando o anterior até o fim desse período de sobreposição. Sua resposta não é assinada: o Bird valida o certificado TLS do seu receptor, e a conexão HTTPS autentica o que ele retorna.

Verifique os cabeçalhos sobre o corpo bruto com a chamada verify de uma biblioteca Standard Webhooks antes de fazer o parsing. O webhooks.unwrap dos SDKs faz o parsing de eventos da plataforma e não serve para essas solicitações. Primeiro, gere um novo segredo em Webhooks → Direct callbacks, porque o segredo inicial nunca é exibido. A assinatura mostra que alguém que possui o segredo do seu espaço de trabalho assinou a solicitação. Seus receptores de callback SMS têm o mesmo segredo e também podem assinar, então mantenha-o apenas em receptores de sua confiança. Qualquer pessoa que possa editar as sequências do espaço de trabalho escolhe a URL e data. Confira se target_url é a sua própria URL para recusar uma solicitação que o Bird assinou para outro receptor, e autorize as ações de negócio no seu receptor. A autorização do cliente nunca é repassada.

As solicitações de webhook da sequência não apresentam certificado de cliente, mesmo quando seu espaço de trabalho exige mTLS. Configure o receptor para aceitar conexões sem certificado de cliente e, em vez disso, autentique a solicitação assinada.

Compare o webhook-timestamp assinado, um timestamp Unix em segundos, com um relógio de servidor sincronizado. Rejeite solicitações com mais de cinco minutos no passado ou no futuro. Elimine duplicatas por webhook-id antes de executar efeitos colaterais. Sempre que possível, armazene o ID e o resultado de forma atômica junto com a ação, e retorne o resultado salvo quando a solicitação se repetir. Cada continuação tem seu próprio ID. Use uma chave de idempotência de negócio separada se solicitações distintas não puderem repetir a mesma ação.

Retorne dados

O receptor retorna esta estrutura de resposta fechada:

Exemplo de código
{
  "schema_version": 1,
  "type": "outcome",
  "output": { "status": "confirmed", "message": "Your appointment is confirmed." }
}

output precisa corresponder ao schema configurado. A resposta retorna dados, não uma porta, um ID de nó ou novos comandos. Uma continuação é {"schema_version":1,"type":"continue","url":"https://example.com/voice/next"} na origem canônica da URL original.

Para rotear com base nos dados, conecte success a uma etapa logic.branch com casos como steps.decision.output.status == 'confirmed'. Declare o campo como uma string enum no schema para que o receptor só possa retornar esses valores.

A solicitação contém a identidade da execução, da sessão e da chamada, a identidade da sequência admitida e do nó, seu data materializado e results. Mantenha a entrada de negócio em data. Um resultado privado direto de Gather pode aparecer uma única vez em results, e gravações concluídas trazem um ID quando disponível. Essas observações não se tornam campos de expressão automaticamente.

Ler a solicitação recebida pelo receptor

Uma execução de teste de rascunho envia este formato. Os IDs e timestamps abaixo são fictícios; a solicitação real usa a execução admitida e a ocorrência atual do nó:

Exemplo de código
{
  "schema_version": 1,
  "method": "POST",
  "target_url": "https://example.com/decision",
  "run_id": "vsr_01k5yb7p000000000000000000",
  "sequence": {
    "id": "vsq_01k5yb7p000000000000000000",
    "version_id": null,
    "draft_revision": 1,
    "entry_node_id": "start",
    "mode": "test"
  },
  "session_id": "vcs_01k5yb7p000000000000000000",
  "call": { "id": "vcl_01k5yb7p000000000000000000", "orig": null, "dest": null },
  "node": { "id": "decision", "occurrence_id": "00000000-0000-4000-8000-000000000001" },
  "data": { "appointment_id": "appointment_123" },
  "results": []
}

Em uma execução publicada, version_id identifica a versão selecionada e draft_revision é nulo. Em uma chamada que executou uma definição inline, id, version_id e draft_revision são todos nulos. mode pode ser test ou production. Origem e destino usam objetos de participante da chamada anuláveis. Verifique a assinatura antes de confiar nesses campos de identidade.

Uma observação de Gather em results tem type: "gather", node_id, o UUID command_id, digits e reason. Uma observação de gravação tem type: "recording", o UUID command_id, state e um recording_id quando disponível. Use os dígitos privados apenas na solicitação a que se destinam; eles não se tornam saídas de expressão retidas. As solicitações de continuação mantêm a mesma ocorrência do nó, e as observações já entregues são removidas de results.

Tratar falhas

Uma amostra técnica usa a porta failure com {"code":"webhook_unavailable"} ou {"code":"webhook_invalid_response"}. Uma falha conectada segue o caminho de recuperação; uma falha não conectada faz a execução falhar. Um success não conectado encerra a execução normalmente. As solicitações de webhook reais têm um prazo de três segundos e não são tentadas novamente de forma automática. O Preview não faz nenhuma solicitação.

O prazo de três segundos inclui a leitura do segredo de assinatura. Conecte failure a um caminho de recuperação para que a chamada possa continuar quando o receptor estiver indisponível ou retornar uma resposta inválida. Uma solicitação que excedeu o tempo limite pode já ter causado um efeito colateral no receptor.

Trate data, a identidade da chamada e os dígitos do Gather como privados. Restrinja o acesso ao receptor e ao segredo, evite registrar corpos ou segredos em logs e retenha a entrada do chamador apenas pelo tempo que sua aplicação precisar. Não coloque dados privados nem credenciais em URLs, porque o rastreamento da chamada retém a URL completa, incluindo a query. A URL e os dados configurados e a saída validada ficam retidos no histórico de execução; os dígitos transitórios do Gather são excluídos da entrada capturada da etapa. Retorne apenas os dados de que a sequência precisa.

Leia os dados retornados em steps.decision.output e os erros técnicos em steps.decision.error.code. Se os dois caminhos se encontrarem, proteja o wrapper com has(steps.decision.output) ou has(steps.decision.error) antes de usá-lo. Um 200 HTTP do seu receptor só indica um resultado válido depois que o corpo passa pelo contrato.

Continue com a documentação, guias e exemplos sobre este tópico.