Pular para o conteúdo principal

API de Simulação de Jornadas

A API de Simulação de Jornadas permite que sistemas externos (como agentes de IA) interajam com jornadas de forma conversacional sem enviar mensagens reais pelo WhatsApp. Isso é útil para testes, pré-visualizações e integração da lógica de jornadas em fluxos de trabalho externos.

atenção

Esta API está em desenvolvimento ativo e mudanças incompatíveis são esperadas nos próximos meses. A compatibilidade com versões anteriores não é garantida até pelo menos agosto de 2026.

A autenticação ocorre como em outras chamadas de API, com um token da Turn.io especificado no header HTTP Authorization, prefixado por Bearer e seguido de um token emitido pela interface do usuário da Turn.io.

Como funciona​

O endpoint de simulação utiliza uma única rota POST que gerencia tanto a criação de novas simulações quanto o envio de entradas para simulações existentes:

  • Se não existir uma simulação para o simulation_id fornecido: uma nova sessão de simulação é criada e a jornada começa a ser executada.
  • Se já existir uma simulação para o simulation_id fornecido: a entrada (input) fornecida é enviada para a sessão existente.

O simulation_id é sempre obrigatório e fornecido pelo chamador. Pode ser qualquer identificador de string entre 6 e 64 caracteres, então um UUID funciona. O endpoint usa a combinação do número ao qual o seu token pertence, do UUID da jornada (da URL) e do simulation_id (do corpo da requisição) para identificar sessões de simulação, então outro número usando o mesmo simulation_id nunca chega à sua sessão.

Iniciando uma simulação​

Para iniciar uma nova simulação, faça a seguinte requisição:

$ curl -X POST "https://whatsapp.turn.io/v1/journeys/<uuid-da-jornada>/simulation" \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{
"simulation_id": "minha-sessao-001",
"revision": "production",
"contact": {
"name": "Usuário Teste",
"language": "eng"
}
}'

> {
"state": "waiting_for_input",
"message": "Bem-vindo! Qual é o seu nome?",
"context": {
"contact": {
"name": "Usuário Teste",
"language": "eng"
}
}
}

Parâmetros​

NomeObrigatórioPadrãoDescrição
simulation_idsimUm identificador de string fornecido pelo chamador (6 a 64 caracteres) para rastrear a sessão.
revisionnão"production"Qual revisão da jornada simular. Deve ser "production" ou "staging".
contactnão{}Um objeto com atributos de contato para preencher o contexto do contato simulado. Definir um campo reservado como null o limpa, o que é útil para simular contatos sem whatsapp_id.
parentnãoUm objeto exposto à jornada como @parent.*, para simular uma jornada do tipo função invocada por uma jornada pai. Variáveis reservadas (chat, contact, event, global, number, organisation) são ignoradas.
childnãoUm objeto exposto à jornada como @child.*, para simular uma jornada retomando após o término de uma jornada filha. Variáveis reservadas são ignoradas, como em parent.
inputnãoA primeira mensagem do contato. A jornada responde logo após a abertura, e message traz as duas.
http_mocksnão[]Respostas fixas para as requisições HTTP que as skills da jornada fazem, veja Simulando chamadas HTTP.
fail_unmocked_http_callsnãofalseQuando true, uma requisição que nenhum mock responde falha dentro da skill em vez de sair de verdade.

Campos da resposta​

NomeDescrição
simulation_idO identificador da sessão de simulação.
stateO estado atual da simulação: "waiting_for_input" (a jornada espera uma resposta) ou "end" (a jornada terminou).
messageA saída de texto da jornada. Inclui conteúdo de mensagem, opções de botões e URLs de mídia.
cardO nome do card em que a jornada está após este turno.
optionsOs rótulos dos botões ou itens de lista que a jornada ofereceu neste turno, por exemplo ["Yes, I agree", "No, thanks"]. O texto da mensagem também os lista, com instruções para um agente de IA que conduz a simulação.
skill_callsAs skills que os agentes de IA da jornada chamaram neste turno, em ordem, cada uma com name, arguments e output.
actionsAs ações para as quais os agentes de IA da jornada encaminharam neste turno, por exemplo ["book_appointment"]. Vazio quando o agente continuou a conversa.
http_callsAs requisições HTTP que as skills da jornada fizeram neste turno, simuladas ou não, cada uma com method, url, headers, body, json (o corpo lido como JSON, quando for), query, params (os valores capturados pelos marcadores :nome do mock), status, mocked e failures.
contactOs campos do contato simulado, os mesmos de context.contact, incluindo o que a jornada escreveu neles neste turno.
contextO contexto de variáveis atual da simulação, incluindo campos de contato e variáveis definidas pela jornada. Retornado a cada turno, então escritas de contato que acontecem após uma resposta são observáveis. Conexões de IA nele vêm sem o token do fornecedor.

Testando uma jornada fora do Turn​

Cada resposta diz o que a jornada fez naquele turno, então uma suíte de testes externa pode verificar mais do que o texto da resposta: em qual card a jornada está, quais skills os agentes de IA chamaram e com quais argumentos, para qual ação encaminharam e quais requisições HTTP as skills fizeram.

Simulando chamadas HTTP​

Skills que chamam uma API por turn.http.request podem receber respostas fixas, para que um teste não dependa da API real e possa testar o que acontece quando ela falha. Cada mock aceita um method opcional, um padrão de url (* corresponde a qualquer coisa, :nome corresponde a um segmento do caminho e aparece em params da chamada) e a response a devolver (status é 200 por padrão, um body objeto é enviado como JSON):

$ curl -X POST "https://whatsapp.turn.io/v1/journeys/<journey-uuid>/simulation" \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{
"simulation_id": "booking-test-01",
"revision": "staging",
"fail_unmocked_http_calls": true,
"http_mocks": [
{
"method": "GET",
"url": "https://clinic.example.com/api/slots/:day",
"response": { "body": { "slots": ["09:00", "11:30"] } }
}
],
"input": "Can I come in on Monday?"
}'

> {
"state": "waiting_for_input",
"message": "Hi! How can I help you today?\nWe have Monday openings at 09:00 and 11:30. Which one would you like?",
"card": "Agent",
"skill_calls": [
{
"name": "find_slots",
"arguments": { "day": "monday" },
"output": "free slots on monday: 09:00, 11:30"
}
],
"actions": [],
"http_calls": [
{
"method": "GET",
"url": "https://clinic.example.com/api/slots/monday",
"params": { "day": "monday" },
"status": 200,
"mocked": true,
"failures": [],
...
}
],
"context": { ... }
}

Os mocks que correspondem respondem na ordem da lista, uma requisição cada, e o último que corresponde continua respondendo quando a lista acaba, então dois mocks na mesma url formam uma sequência. Uma requisição que nenhum mock responde sai de verdade e aparece em http_calls com mocked: false, a menos que fail_unmocked_http_calls seja true. Nesse caso ela falha dentro da skill e o motivo fica em failures da chamada.

http_mocks enviados com uma mensagem posterior são adicionados aos que a simulação já tem, então um teste pode mudar o que a API responde no meio de uma conversa.

Enviando entrada para uma simulação​

Quando uma simulação está no estado waiting_for_input, envie a entrada do usuário fazendo outra requisição com o mesmo simulation_id:

$ curl -X POST "https://whatsapp.turn.io/v1/journeys/<uuid-da-jornada>/simulation" \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{
"simulation_id": "minha-sessao-001",
"input": "Santiago"
}'

> {
"state": "end",
"message": "Obrigado Santiago! Seu cadastro está completo."
}

Parâmetros​

NomeObrigatórioDescrição
simulation_idsimO mesmo ID de simulação usado ao iniciar a sessão.
inputsimA resposta do usuário como uma string. Deve ser não vazia.
http_mocksnãoMais mocks HTTP, adicionados aos que a simulação já tem.

Exemplo de múltiplos turnos​

Uma simulação típica de múltiplos turnos envolve iniciar a jornada e depois enviar entradas para cada etapa que requer uma resposta.

Etapa 1: Iniciar a jornada

$ curl -X POST "https://whatsapp.turn.io/v1/journeys/d144cb30-f759-4260-82ba-07353f0e389f/simulation" \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{
"simulation_id": "sessao-demo-01",
"revision": "production",
"contact": {
"name": "Maria",
"language": "eng"
}
}'

> {
"state": "waiting_for_input",
"message": "Olá Maria! Como podemos ajudá-la hoje?\n\nResponda exclusivamente com uma das seguintes opções:\nAgendar consulta\nVerificar status\nFalar com atendente",
"context": {
"contact": {
"name": "Maria",
"language": "eng"
}
}
}

Etapa 2: Enviar entrada do usuário

$ curl -X POST "https://whatsapp.turn.io/v1/journeys/d144cb30-f759-4260-82ba-07353f0e389f/simulation" \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{
"simulation_id": "sessao-demo-01",
"input": "Agendar consulta"
}'

> {
"state": "waiting_for_input",
"message": "Ótimo! Qual data funciona para você?"
}

Etapa 3: Continuar a conversa

$ curl -X POST "https://whatsapp.turn.io/v1/journeys/d144cb30-f759-4260-82ba-07353f0e389f/simulation" \
-H "Authorization: Bearer token" \
-H "Content-Type: application/json" \
-d '{
"simulation_id": "sessao-demo-01",
"input": "Próxima segunda-feira"
}'

> {
"state": "end",
"message": "Sua consulta está agendada para a próxima segunda-feira. Até lá!"
}

Respostas de erro​

A API retorna códigos de status HTTP e mensagens de erro apropriados:

StatusErroDescrição
400simulation_id is requiredO campo simulation_id está ausente no corpo da requisição.
400simulation_id must be between 6 and 64 charactersO simulation_id é muito curto ou muito longo.
400Invalid Journey UUIDO UUID da jornada na URL não é um UUID válido.
400Journey has no published production revisionA jornada não possui uma revisão de produção publicada.
400Journey has no staging revisionA jornada não possui uma revisão de staging (quando revision é "staging").
400Journey is disabledA jornada está desativada.
400Journey has been deletedA jornada foi excluída.
400Invalid revision, must be 'production' or 'staging'Um valor inválido de revision foi fornecido.
400Invalid parent, must be an objectO campo parent foi fornecido, mas não é um objeto.
400Invalid child, must be an objectO campo child foi fornecido, mas não é um objeto.
400Invalid input, must be a non-empty stringO campo input está vazio ou não é uma string.
400Invalid http_mocks: ...Um mock em http_mocks está malformado. A mensagem diz qual parte.
404Journey not foundNenhuma jornada existe com o UUID fornecido.
404Simulation not found or expiredA sessão de simulação expirou ou não existe.

Observações​

  • As sessões de simulação são efêmeras e expiram após um período de inatividade. Se uma sessão expirar, inicie uma nova com um simulation_id diferente.
  • Nenhuma mensagem real do WhatsApp é enviada durante uma simulação. A lógica da jornada é executada em memória.
  • Conteúdo de mídia (imagens, vídeos, áudio, documentos) nas mensagens da jornada é retornado como texto descritivo com URLs, por exemplo: "Image available at: https://...".
  • Quando a jornada inclui opções de botões ou listas, elas são adicionadas ao texto da mensagem, uma opção por linha.
  • Campos de contato escritos pela jornada são refletidos em context no turno em que acontecem, então uma escrita que ocorre após uma resposta pode ser verificada diretamente, em vez de inferida a partir do texto da mensagem.
  • Blocos de agente de IA com memória ativada mantêm o contexto da conversa entre os turnos da simulação, permitindo que a IA faça referência a mensagens anteriores na sessão.
  • As chamadas de IA que uma simulação faz não aparecem nos AI Logs, para que suítes de teste que repetem muitas conversas não os encham de sessões de teste.