Visão geral das Jornadas
As Jornadas são o recurso para criar serviços de impacto na Turn.io. As Jornadas foram fortemente inspiradas pelas ideias originais do Hypercard e do Hypertalk.
As Jornadas eram previamente chamadas de stacks. As palavras "stacks" e "jornadas" podem ser usadas de forma intercambiável em nossa documentação, e você ainda pode ver o uso de stacks em alguns nomes de função.
Na Turn.io, as Jornadas são contêineres que contêm um ou mais cards e os relacionamentos entre eles. Os cards executam as diversas etapas que compõem seu serviço de impacto usando funções e expressões.
As funções e expressões disponíveis são descritas abaixo, com exemplos e erros comuns.
Linguagem de codificação das Jornadas
Serviços de impacto construídos usando jornadas são descritos usando uma linguagem de codificação personalizada. Às vezes, nos referimos a ela como a DSL das Jornadas (Domain Specific Language).
Vamos analisar a estrutura e a sintaxe da linguagem de código.
Bloco de código da Jornada
Pense em uma jornada como um contêiner que contém vários cards.
Bloco de código do Card
Pense em um card como executando uma ou mais etapas em seu serviço de impacto. Os cards fazem uso de várias funções e expressões para descrever essas etapas.
Exemplo
O exemplo a seguir cria um card vazio para fins ilustrativos.
card CardName do
...
end
Pontos importantes
- A estrutura de código para criar um card é semelhante à estrutura de código para criar uma jornada.
- Seu bloco de código de card sempre será definido dentro de um bloco de código de jornada.
- Seu card deve ter um nome.
- O comando
doinicia o card. - O comando
endconclui o card. - Toda a lógica do card será adicionada entre os comandos do e end.
- A lógica consistirá em funções, expressões etc. Veja os exemplos abaixo.
Usando comentários
Qualquer linha de texto em sua jornada prefixada com um sinal # se tornará um comentário. Isso significa que não será uma linha de código executável, sendo ignorada quando a jornada for executada.
card MyCard do
# Este é um comentário
end
Documentando suas Jornadas
Comentários de código são ótimos para documentar linhas individuais dentro de um Card, mas às vezes podem ser limitados. Quando se deseja descrever preocupações mais amplas, como fornecer mais detalhes sobre decisões específicas de design, fazer links para documentação ou pesquisa externas, ou descrever detalhes-chave de implementação, os blocos de documentação em Markdown são o ideal.
Você pode usar comentários em Jornadas de Canvas e blocos Markdown em Jornadas de Código
Sua primeira jornada
Agora que sabemos que uma jornada contém um ou mais cards, e cada card contém lógica que descreve seu serviço de impacto, vamos juntar tudo. O exemplo mostra como blocos de jornada e blocos de card se encaixam para criar uma jornada muito simples.
Exemplo
O exemplo a seguir cria uma jornada simples que envia uma única mensagem de texto para um usuário, dizendo "Hello World!".
card MyCard do
text("Oi Mundo!")
end
Relacionando cards
Os cards descrevem as etapas do seu serviço de impacto. Cada card descreve um ponto específico em uma série de interações.
O primeiro card é sempre o que a jornada inicia. Depois disso, a ordem em que os cards aparecem no código da jornada não é importante. O que é importante é descrever os relacionamentos entre os cards, pois isso determina como os usuários navegarão entre eles.
Existem duas formas principais de descrever o que acontece após cada card, ou seja, a then ou a condição when.
A condição then
O relacionamento then é usado para conectar um card a outro.
Sintaxe
card FirstCard do
text("Hello world!")
then(NextCard)
end
Também suportamos uma sintaxe mais antiga, que especifica o próximo cartão para navegar para todo o cartão.
Sugerimos usar a função then() no final de um cartão, mas você ainda pode encontrar essa sintaxe em playbooks e exemplos de código:
card FirstCard, then: NextCard do
text("Oi Mundo!")
end
Exemplo
Este exemplo mostra como usar a função then para indicar quando um card deve ser imediatamente seguido por outro card. Neste caso, duas mensagens de texto serão enviadas uma após a outra, primeiro "this is the first card" e depois "this is the second card".
card One do
text("esse é o primeiro card")
then(Two)
end
card Two do
text("esse é o segundo card")
end
Pontos importantes
- Sem
then, apenas a primeira mensagem de texto será enviada.
A condição when
A cláusula when é usada para adicionar condições que controlam a ordem de execução de um card.
Você pode incluir isso na função then dentro de um card, ou descrever a condição no início de um card.
Sintaxe
Novo estilo:
card CardName do
...
then(HappyPath when alguma_condicao)
then(CardError)
end
card HappyPath do
text("Bem vindo!")
end
card CardError do
text("Desculpe, não podemos te ajudar")
end
Estilo antigo com correspondência de padrões do card - observe que neste caso temos 2 cards com o mesmo nome, mas com diferentes condições sob as quais seriam executados:
card CardName, then: ProcessContact do
...
end
card ProcessContact when alguma_condicao do
text("Welcome!")
end
card ProcessContact do
text("Sorry, we cannot help you")
end
Observe que no estilo mais antigo de navegação, a sintaxe then usava uma vírgula e dois-pontos (NomeDoCartão, then:).
No entanto, when deve ocorrer imediatamente após o cardName sem vírgula ou dois pontos.
Operadores Booleanos
Esta é uma lista das funções de comparação que podem ser usadas nas Jornadas:
<- menor que>- maior que>=- maior ou igual a<=- menor ou igual a=- igual a==- igual a!=- diferente de<>- diferente de
Eles podem ser combinados com os operadores padrão and e or, bem como a palavra-chave not.
Você pode usar parênteses para determinar a ordem de avaliação:
(true or false) and falseserá avaliado comofalsetrue or (false and false)será avaliado comotrue
Por fim, no que diz respeito a valores truthy e falsey:
- variáveis que são nil ou null serão avaliadas como
false - simplesmente verificar se uma variável não é o valor booleano
trueresultará emfalse. Então qualquer uso dewhen some_variable doserá avaliado como false. Caso contrário, você deve incluir uma comparação. Por exemplo, algumas linguagens podem declarar que uma string não vazia ou uma lista não vazia é avaliada como verdadeiro, mas não é o caso nas Jornadas.
Se você não tiver certeza sobre o valor de uma expressão, pode usar a função log para visualizar a saída no simulador.
Exemplo
O exemplo a seguir elabora um pouco o exemplo anterior, introduzindo condições entre cards.
card One, then: Two do
text("esse é o segundo card")
idade = ask("Qual é a sua idade?")
then(Boomer when idade > 18)
then(OlderTeen when idade > 16 and idade <= 18)
then(CatchAll)
end
card Boomer do
text("olá boomer")
end
card OlderTeen when age > 16 and age <= 18 do
text("Eae!")
end
card CatchAll do
text("Este serviço é \"too cool\" para você")
end
Agora a mesma lógica, mas usando o estilo antigo; você vai notar que o card Um prossegue para o card Dois com a palavra-chave then: . Uma diferença importante aqui é que estamos usando a função ask() que espera a entrada do usuário antes de prosseguir.
O card Two é definido várias vezes, dois deles têm condições que protegem o card. Dependendo da resposta do usuário, o sistema selecionará automaticamente o card Three para o qual a condição seja avaliada como true. O último card Two não tem condição, o que significa que sempre será avaliado como true, funcionando como um fallback padrão.
card One, then: Two do
text("esse é o segundo card")
idade = ask("Qual é a sua idade?")
end
card Two when idade > 18 do
text("Olá boomer")
end
card Two when idade > 16 and idade <= 18 do
text("Eae!")
end
card Two do
text("Este serviço é \"too cool\" para você")
end
Gatilhos (Triggers)
Os Gatilhos (Triggers) são definidos no início da sua jornada e especificam quando sua jornada deve ser executada. Por exemplo, você pode usar o Gatilho (Trigger) a seguir para iniciar sua jornada quando um usuário enviar a mensagem "hi" para o seu serviço:
trigger(on: "MESSAGE RECEIVED") when has_phrase(event.message.text.body, "hi")
card FirstCard do
text("Welcome!")
end
Uma vez acionada (triggered), a jornada começará a ser executada a partir de seu primeiro card.
Um Gatilho (Trigger) é composto por um evento, como MESSAGE RECEIVED, e uma expressão opcional (especificada após a palavra-chave when) que pode ser usada para corresponder às propriedades da mensagem recebida e/ou do contato.
Existem dois tipos de Gatilhos (Triggers):
- Mensagens Gatilho de Entrada: estes Gatilhos (Triggers) são executados quando um usuário envia uma mensagem para o seu serviço.
- Gatilhos Temporais: estes Gatilhos (Triggers) são executados em uma data/hora específica ou algum tempo antes/depois de um evento específico (como "2 horas após o cadastro"). Eles também podem ser configurados para serem executados periodicamente em uma programação (como "toda segunda-feira às 15:00").
Dividimos os aspectos de código dos gatilhos nas seções a seguir, mas você também pode aprender fazendo: crie um gatilho (trigger) no canvas sem código e depois mude para a visualização de código para ver o código gerado. Observe que o código é somente leitura e você não pode editá-lo diretamente:

Mensagens Gatilho de Entrada
Esses Gatilhos (Triggers) são executados quando um contato envia uma mensagem para o seu serviço. Os seguintes eventos são suportados:
MESSAGE RECEIVED: aciona quando um contato envia uma mensagem para o seu serviço.FIRST TIME: aciona quando um contato envia uma mensagem para o seu serviço pela primeira vez.CATCH ALL: aciona se nenhum Gatilho (Trigger) (ou Automação) tratou a mensagem recebida.
Você pode refinar ainda mais o Gatilho (Trigger) fornecendo uma expressão que corresponda às propriedades da mensagem recebida e/ou do contato que enviou a mensagem.
O exemplo a seguir corresponde a mensagens que contêm a palavra "hi", mas somente para contatos que optaram por participar (opted in):
trigger(on: "MESSAGE RECEIVED")
when has_phrase(event.message.text.body, "hi") and contact.opted_in == true
card FirstCard do
text("Welcome opted-in user!")
end
Na expressão, você pode se referir à mensagem recebida com event.message (e seu conteúdo com event.message.text.body) e ao contato que enviou a mensagem com contact. Para se referir a campos de perfil de contato, você pode usar a sintaxe contact.field_name_here.
Você também pode criar um gatilho que verifica se a mensagem enviada era uma mídia (imagem, vídeo, áudio) em vez de um texto. Mais informações sobre como configurar esse gatilho podem ser encontradas aqui.
As seguintes Expressões são suportadas em Mensagens Gatilho de Entrada:
- has_all_members
- has_any_member
- has_any_beginning
- has_any_end
- has_any_exact_phrase
- has_any_phrase
- has_all_words
- has_any_word
- has_beginning
- has_date
- has_date_eq
- has_date_gt
- has_date_lt
- has_email
- has_end
- has_group
- has_member
- has_number
- has_number_eq
- has_number_gt
- has_number_gte
- has_number_lt
- has_number_lte
- has_only_phrase
- has_only_text
- has_pattern
- has_phone
- has_phrase
- has_text
- has_time
- isbool
- is_nil_or_empty
- isnumber
- isstring
Todos os operadores booleanos e sintaxe discutidos para declarações when são suportados em um gatilho de mensagem.
Gatilhos Temporais
Os Gatilhos Temporais são executados em uma data/hora específica ou algum tempo antes/depois de um evento específico (como "2 horas após o cadastro"). Eles também podem ser configurados para serem executados periodicamente em um cronograma (como "toda segunda-feira às 15:00").
Os seguintes Gatilhos Temporais são suportados:
- Data específica: aciona em um datetime específico, por exemplo:
trigger(at: "2024-09-13T15:45:00Z"). - Recorrente: aciona em uma programação recorrente de estilo cron, por exemplo:
trigger(every: "30 15 * * MON"). - Relativo a um campo de perfil: aciona algum tempo antes/depois do valor datetime contido em um campo de perfil de contato, por exemplo:
trigger(interval: "+3d", relative_to: "contact.due_date").
Assim como nos Mensagens Gatilho de Entrada, é possível refinar ainda mais o Gatilho (Trigger) fornecendo uma expressão após a palavra-chave when. A expressão atua como um filtro para seus contatos: o gatilho (trigger) será executado para todos os contatos para os quais a expressão retornar true.
Como exemplo, o seguinte Gatilho (Trigger) será executado todas as terças-feiras às 10:30 para todos os contatos que tiverem o campo de perfil is_pregnant definido como true:
trigger(every: "30 10 * * TUE") when contact.is_pregnant == true
As seguintes Expressões são suportadas em Gatilhos Temporais:
Todos os operadores booleanos e sintaxe discutidos para declarações when são suportados em um gatilho temporal.
Uma observação importante sobre modelos (templates) de mensagem: ao usar Gatilhos Temporais, muitas vezes é difícil dizer se o gatilho (trigger) será executado dentro da janela de serviço de 24 horas do WhatsApp para um contato. Como o WhatsApp só permite o envio de modelos (templates) de mensagem fora da janela de serviço de 24 horas, recomendamos fortemente o uso de modelos (templates) de mensagem (em vez de mensagens normais) em jornadas que usem Gatilhos Temporais.
Gatilhos de data específica
Gatilhos de data específica serão executados na datetime especificada para todos os contatos para os quais a expressão fornecida for avaliada como true.
O datetime é fornecido com o parâmetro at: e deve ser uma string datetime válida em formato ISO8601.
Por exemplo, a jornada a seguir será acionada às 15:45 em 13 de setembro de 2024 para todos os contatos que tiverem o campo opted_in definido como true ou o campo registration_status definido como "completed".
trigger(at: "2024-09-13T15:45:00Z") when
contact.opted_in == true or contact.registration_status == "completed"
Gatilhos Recorrentes
Gatilhos recorrentes serão executados em uma programação recorrente especificada usando uma cron schedule expression.
Recomendamos usar o site Crontab Guru para construir e validar sua expressão cron. Observe que as expressões cron serão avaliadas no fuso horário UTC.
Também é possível especificar uma data de término para o gatilho recorrente informando o parâmetro opcional until. O parâmetro until precisa ser um valor datetime válido no formato ISO8601.
Por exemplo, o seguinte gatilho será executado toda segunda-feira às 15:30 (até 13 de setembro de 2025) para todos os contatos que tiverem o campo language definido como qualquer valor diferente de "eng".
trigger(every: "30 15 * * MON", until: "2025-09-13T15:45:00Z") when
not has_phrase(contact.language, "eng")
Gatilhos relativos a um campo de perfil
Esses gatilhos são executados em um intervalo de tempo especificado em relação ao valor datetime contido em um campo de perfil.
Por exemplo, podem ser usados para acionar uma jornada 2 horas após um contato se inscrever em um programa:
trigger(interval: "+2h", relative_to: "contact.enrolled_at") when
has_phrase(contact.project_enrolled, "project_a")
O intervalo de tempo relativo é fornecido como o argumento interval e deve ser uma string composta pelos seguintes elementos:
- Sinal
+ou-, onde+significa depois e-significa antes. - Um inteiro
- Uma unidade de tempo das seguintes suportadas:
mpara minutos.hpara horas.dpara dias.wpara semanas.Mpara meses.
O campo de contato deve ser do tipo data e deve ser especificado como o argumento relative_to usando a sintaxe "contact.field_name".
O exemplo a seguir envia uma mensagem ao usuário 3 dias antes do aniversário dele:
trigger(interval: "-3d", relative_to: "contact.birthday")
card UpcomingBirthday do
send_message_template("birthday_3d_before", "en", [])
end
Também é possível substituir a hora em que o gatilho (trigger) deve ser executado usando a opção target_time (especificada como uma string de hora UTC ISO8601 válida). Isso é útil quando se usam unidades de intervalo como dias/semanas/meses para evitar enviar mensagens em horários inconvenientes.
Por exemplo, o seguinte Gatilho (Trigger) será executado 2 semanas antes do valor datetime do campo due_date do contato, exatamente às 15:30:
trigger(interval: "-2w", relative_to: "contact.due_date", target_time: "15:30:00") when
contact.is_expecting == true
Gatilhos Globais (Gatilhos Interrompedores)
Os Gatilhos Globais permitem que uma jornada funcione como um "botão de início" universal que pode interromper qualquer fluxo em que o usuário esteja e iniciar esta jornada em seu lugar. Exemplos típicos são palavras‑chave como "menu", "home", "help" ou "start over" que devem sempre levar as pessoas a uma jornada designada.
Para fazer um gatilho interromper outras jornadas, marque um gatilho de mensagem de entrada como global.
Sintaxe
trigger(on: "MESSAGE RECEIVED", global: true)
when has_any_exact_phrase(event.message.text.body, ["menu", "home", "start over", "help"])
card FirstCard do
text("Bem-vindo! Você voltou ao menu principal.")
end
Como funciona
- Quando uma mensagem corresponde a um gatilho global, ele interrompe imediatamente qualquer jornada em execução para aquele contato e inicia esta jornada a partir do primeiro card.
- Apenas gatilhos de mensagem de entrada podem ser globais.
- Defina o gatilho global na jornada que você deseja iniciar quando a palavra‑chave for detectada (por exemplo, sua jornada de menu principal).
Exemplos
-
Menu inicial: forneça a palavra "menu" que sempre leve os usuários de volta ao menu principal, criando uma maneira tranquilizadora de se recuperar quando se perderem em um fluxo longo.
trigger(on: "MESSAGE RECEIVED", global: true)
when has_only_phrase(event.message.text.body, "menu")
card HomeMenu do
text("Menu principal")
# ... apresentar opções
end -
Falar com uma pessoa: permita que os usuários digitem "agent" a qualquer momento para saltar para uma jornada de suporte humano.
trigger(on: "MESSAGE RECEIVED", global: true)
when has_only_phrase(event.message.text.body, "agent")
card ConnectToHuman do
text("Vamos conectá-lo a uma pessoa.")
# ... fluxo de handover
end -
Invocar um assistente de IA: permita uma palavra‑chave como "assistant" para direcionar o usuário a uma jornada de triagem de IA de qualquer lugar.
trigger(on: "MESSAGE RECEIVED", global: true)
when has_only_phrase(event.message.text.body, "assistant")
card AIRouter do
text("Como posso ajudar?")
# ... lógica de roteamento de IA
end
Boas práticas
- Informe os usuários: mencione as palavras‑chave de escape em pontos de entrada ou durante fluxos mais longos para que as pessoas saibam que elas existem.
- Mantenha as palavras‑chave simples: escolha termos intuitivos e fáceis de lembrar. Evite palavras que surjam naturalmente em conversas, a menos que restrinja a correspondência (por exemplo, use
has_only_phrase). - Reserve para casos especiais: muitos gatilhos globais aumentam interrupções acidentais e prejudicam a experiência. Mantenha a lista pequena e com propósito.
Variáveis
Como em muitas linguagens de programação, variáveis podem ser usadas para armazenar valores. Todas as variáveis declaradas em uma jornada estão disponíveis para todos os cards da jornada, e não apenas no card em que a variável foi criada.
Os valores atribuídos às variáveis estão disponíveis apenas durante a execução da jornada e serão perdidos quando o usuário terminar de interagir com a jornada. Se você precisar salvar dados para recuperação posterior (por exemplo, para recuperá-los de outras jornadas no futuro), consulte sobre contato profiles.
card CardOne do
first = 2
then(CardTwo)
end
card CardTwo do
second = 3
result = first + second
then(CardThree)
end
card CardThree do
# Isso envia a mensagem "The result is: 5"
text("The result is: @result")
end
Interagindo com o objeto 'event'
As jornadas podem receber e processar diferentes tipos de mensagens dos usuários: texto, imagens, vídeos, áudio, documentos e dados de localização. A compreensão de como trabalhar com esses tipos de mensagens começa com a variável event que pode ser acessada usando @event.
A Variável event
Quando um usuário envia uma mensagem, a Turn.io cria uma variável event que contém todas as informações sobre essa mensagem. Isso inclui o conteúdo da mensagem, informações do remetente, tipo de mensagem e metadados de mídia.
Estrutura do Event
Veja um exemplo da estrutura da variável event quando um usuário envia uma imagem:
%{
"message" => %{
"_vnd" => %{
"v1" => %{
"author" => %{
"id" => "491111222333",
"name" => "James Doe",
"type" => "OWNER"
},
"chat" => %{
"contact_uuid" => "4468d47c-b8f4-4e7c-859d-0f88075e57b8",
"owner" => "+491111222333",
"state" => "OPEN",
"uuid" => "362eac5a-af1b-4ad9-badc-8deaf48c4645"
},
"direction" => "inbound",
"inserted_at" => ~U[2024-12-05 10:42:24.701578Z],
"uuid" => "05aafc7a-4685-5d9e-8148-13acd50510bd"
}
},
"from" => 491111222333,
"id" => "wamid.HBgNNDkxNz...",
"image" => %{
"caption" => nil,
"id" => "2060181771091421.jpg",
"mime_type" => "image/jpeg",
"sha256" => "uoPd3p1CX0kqeRbCGnUF8UgqYi3uHkwWwbv3BIljI20="
},
"timestamp" => 1733395341,
"type" => "image"
},
"type" => "message"
}
Campos Principais de @event
| Campo | Descrição |
|---|---|
event.message.type | O tipo de mensagem recebida |
event.message.from | O número de telefone do remetente |
event.message.timestamp | Quando a mensagem foi enviada |
event.message._vnd.v1.chat | Informações do chat e do contato |
Acessando o Tipo de Mensagem
O campo mais importante para manipular diferentes tipos de mensagens é @event.message.type. Isso indica qual tipo de mensagem o usuário enviou.
Usando @event.message.type
@event.message.type
Esta expressão retorna um valor string:
| Valor de Retorno | Descrição |
|---|---|
"text" | Mensagens de texto |
"image" | Arquivos de imagem (JPEG, PNG) |
"video" | Arquivos de vídeo |
"audio" | Arquivos de áudio |
"document" | Documentos (PDF, DOCX, etc.) |
"location" | Dados de localização (latitude, longitude) |
Acessando Metadados de Mídia
Quando @event.message.type é um tipo de mídia, campos adicionais ficam disponíveis com informações de mídia:
Para Imagens
@event.message.image.id- ID da mídia para buscar o arquivo@event.message.image.mime_type- Tipo de arquivo (ex: "image/jpeg")@event.message.image.caption- Texto da legenda opcional
Para Vídeos
@event.message.video.id@event.message.video.mime_type@event.message.video.caption
Para Documentos
@event.message.document.id@event.message.document.filename@event.message.document.mime_type
Para Áudio
@event.message.audio.id@event.message.audio.mime_type
Usando Tipo de Mensagem em Triggers
Você pode acionar jornadas automaticamente quando os usuários enviam tipos específicos de mídia em vez de mensagens de texto.
Exemplos de Trigger
Acionar Apenas em Imagens
trigger(on: "MESSAGE RECEIVED") when event.message.type == "image"
Acionar em Imagens ou Vídeos
trigger(on: "MESSAGE RECEIVED") when event.message.type == "image" or event.message.type == "video"
Acionar em Qualquer Mídia (Não Texto)
trigger(on: "MESSAGE RECEIVED") when event.message.type != "text"
Usando o Tipo de Mensagem em Cards
Dentro de uma jornada, você pode usar event.message.type para ramificar fluxos com base no que o usuário envia.
Manipulação Condicional Básica
Use cards CodeBlock com cláusulas when para manipular diferentes tipos de mensagens:
# Manipular mensagens de mídia
card HandleMedia when event.message.type != "text" do
text("Você enviou uma mensagem do tipo @event.message.type")
text("Estou processando sua mídia agora...")
end
# Uma condição padrão que manipula mensagens de texto
card HandleText do
text("Você enviou uma mensagem de texto")
text("Deixe-me ajudá-lo com isso...")
end
Validando Tipos de Mídia Esperados
Quando você pede aos usuários uma mídia específica, valide a resposta deles:
card AskForPhoto, then: ValidPhoto do
ask("Por favor, envie uma foto do seu documento de identificação")
end
# Usuário enviou uma imagem - correto!
card ValidPhoto when event.message.type == "image" do
text("Perfeito! Processando sua foto de identificação...")
update_contact(id_photo: @event.message.image.id)
end
# Usuário enviou outra coisa - errado
card InvalidResponse when event.message.type != "text" do
text("Por favor, envie um arquivo de imagem, não um @event.message.type")
run_stack("AskForPhoto")
end
# Usuário enviou texto - lembre-o
card TextResponse do
text("Preciso de uma foto do seu documento de identificação. Por favor, tire uma foto e envie.")
run_stack("AskForPhoto")
end
Manipulando Múltiplos Tipos de Mídia
card AcceptImageOrVideo when event.message.type == "image" or event.message.type == "video" do
media_type = event.message.type
text("Ótimo! Recebi seu @media_type")
then(NextStep when media_type == "image")
then(NextStepVideo when media_type == "video")
end
card RejectOther do
text("Por favor, envie apenas imagens ou vídeos")
end
Variáveis pais/filhos nas sessões de jornada
Ao criar fluxos de conversação complexos, muitas vezes você precisa criar jornadas modulares em que uma jornada (a principal) inicia outra jornada (a secundária) e, em seguida, retoma após a conclusão da secundária. O Journeys oferece suporte a isso por meio da passagem de variável pai/filho, permitindo que você compartilhe dados entre essas sessões de jornada aninhadas.
A passagem de variáveis pai/filho permite a execução de jornadas hierárquicas:
- Uma jornada pai pode iniciar uma jornada filha
- A jornada secundária recebe automaticamente acesso às variáveis da principal
- Quando a jornada filha é concluída, suas variáveis são passadas de volta para a jornada pai
- O pai pode então continuar a execução com acesso aos resultados do filho
Isso permite fluxos de conversação complexos e de vários estágios com estado compartilhado, mantendo as jornadas individuais focadas e reutilizáveis.
Como funciona a passagem de variáveis
Fluxo de pais para filhos
Quando uma jornada principal gera uma jornada secundária, a secundária recebe automaticamente acesso a todas as variáveis da principal por meio de uma variável parent especial em seu contexto.
Na jornada do filho:
card ChildCard do
# Acessar variáveis da jornada principal
parent_name = parent.user_name
parent_age = parent.user_age
text("Hello @parent_name, I see you're @parent_age years old!")
end
Fluxo do filho para o pai
Quando uma jornada secundária é concluída, todas as suas variáveis são passadas de volta para a jornada principal como um objeto child.
Na jornada dos pais, depois que o filho completa:
card ParentResumeCard do
# Acessar variáveis retornadas da jornada do filho
child_result = child.completion_status
child_score = child.final_score
child_data = child.collected_info
text("Child journey completed with status: @child_result")
text("Final score: @child_score")
end
Tabelas de conteúdo (Content Tables)
Um caso de uso comum ao escrever jornadas é armazenar algum conteúdo de forma que seja fácil interagir com ele a partir de um card.
Um exemplo é um questionário de 10 perguntas. A lógica descrita nos cards não precisa mudar se o conteúdo for atualizado para ter menos ou mais perguntas. Simplesmente queremos percorrer todas as perguntas disponíveis, uma a uma, até que todas sejam respondidas.
Content Tables são ótimas para esses tipos de casos. Elas têm um nome exclusivo e funcionam como uma planilha, permitindo que se especifiquem colunas com nomes e linhas para cada.

Dentro de um card, as linhas da content table podem ser lidas uma a uma usando Expressions.
As tabelas têm um atributo de lista chamado rows que dá acesso a todas as linhas da tabela. Cada valor de linha individual pode ser acessado usando o nome da coluna em minúsculas.
card TextCard do
row = table_0.rows[0]
text("""
The value of the first rows is: @row.column_1, @row.column_2, and @row.column_3
""")
end

Parâmetros
Frequentemente, ao escrever jornadas, haverá partes comuns de texto e valores que são reutilizadas entre os cards. Pense em coisas como o texto de boas-vindas em um botão que leva de volta ao menu principal, por exemplo.
Muitas vezes é desejável apresentar esses elementos comuns em uma interface facilmente editável fora de objetos de código em uma jornada.
Parameters são ótimos para isso, pois permitem atribuir um nome a um elemento comumente reutilizado e fornecer um valor padrão para ele. Ao escrever cards, você pode então se referir a esses valores pelo nome usando Expressions
Os parâmetros são semelhantes às Content Tables, exceto que são otimizados para a leitura de valores individuais em vez de linhas combinadas.
Os valores em parameters são armazenados em um atributo chamado items, de onde as entradas individuais podem ser lidas pelo nome em minúsculas.
card TextCard do
text("""
@parameters_0.items.welcome_text
@parameters_0.items.intro
""")
end

Uso de texto multilinha
O texto multilinha é delimitado por aspas triplas (""") e permite representar facilmente texto que se estende por várias linhas.
card QuestionCard do
ask("""
Welcome!
Is "Jane" your name?
""")
end
Ele também permite que você use aspas (") dentro sem precisar escapá-las:
card Card do
data = parse_json("""
{
"my": "json",
"structure": [1, 2, 3]
}
""")
end
Aspas simples não são mais suportadas para valores de string. Isso era suportado anteriormente, mas, de agora em diante, gerará um erro ao salvar uma jornada.
Se você estiver usando aspas simples como no exemplo a seguir:
map(0..10, &concatenate(&1, ', ')
Use aspas duplas em vez disso:
map(0..10, &concatenate(&1, ", ")
Se você precisar usar aspas em uma string, pode escapá-las com uma barra invertida: \".
map(0..10, &concatenate(&1, "\","))
O bloco de código avisará quando você estiver usando aspas simples na próxima vez que você salvar seu código:

Erros comuns
- Todas as linhas, incluindo as aspas triplas, devem estar indentadas no mesmo nível, conforme o exemplo abaixo.
- Não coloque nenhum texto na mesma linha que as aspas triplas. Por exemplo, não faça
ask("""Welcome, apenasask("""e o texto na linha seguinte.
Formatando texto
O WhatsApp permite que você formate seu texto em negrito, itálico, tachado e monospace.
| Formato | Sintaxe | Exemplo |
|---|---|---|
| Itálico | coloque um sublinhado (_) em ambos os lados do texto | _seu texto_ |
| Negrito | coloque um asterisco (*) em ambos os lados do texto | *seu texto* |
| Tachado | coloque uma til (~) em ambos os lados do texto | ~seu texto~ |
| Monospace | coloque três crases (```) em ambos os lados do texto | seu texto |
Desempenho da Jornada
Ao criar jornadas, incentivamos manter em mente o desempenho; criando serviços rápidos e responsivos para seus usuários finais no WhatsApp. Uma das coisas que fazemos para incentivar um serviço responsivo é definir um tempo limite rígido de 30 segundos para que as Jornadas completem uma única ação ou linha dentro de uma Jornada. Por exemplo, se você depende de várias chamadas de webhook externas para complementar seu serviço, certifique-se de que elas respondam dentro de um tempo razoável para permitir que as conversas fluam de forma natural. Nós fazemos algumas concessões de desempenho para chamadas externas a serviços de IA generativa, mas ainda imporemos um tempo limite eventual nesses serviços.
Retomando uma jornada
Uma jornada pode ser retomada automaticamente mesmo após a expiração da sessão, permitindo a continuidade perfeita da conversa. Isso acontece quando:
- A mensagem é uma resposta a qualquer mensagem de saída (texto ou interativa) dessa jornada
- Foi a última jornada com a qual o contato interagiu
- A resposta é recebida em até 7 dias após a última interação
Isso é particularmente útil para:
- Lidar com respostas atrasadas dos contatos
- Manter o contexto da conversa entre os limites da sessão
- Proporcionar uma experiência de conversação natural mesmo com lacunas na interação
Por exemplo, se a sua jornada enviar uma pergunta e o contato responder várias horas depois que a sessão expirou, a jornada continuará de onde parou e processará a resposta adequadamente.
Isso lida com respostas de texto e respostas interativas (cliques em botões e seleções de listas), já que as respostas interativas fazem referência à mensagem de saída original que continha os elementos interativos.