> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Confirmação de reserva e recuperação de reserva abandonada

> Use eventos personalizados, Journeys e Data Feeds para enviar emails de confirmação de reserva ou recuperação baseados no status da reserva em tempo real.

## Visão Geral

Neste tutorial, você configurará um fluxo de trabalho comum de reserva:

* Enviar um email de confirmação de reserva após um usuário completar uma reserva.
* Enviar um email de recuperação se um usuário iniciar uma reserva mas não completá-la a tempo.

Ao final, você terá:

* Dois Eventos Personalizados (`booking_started`, `booking_complete`)
* Uma Journey que se ramifica entre conclusão vs abandono
* Um Data Feed de reserva para detalhes de confirmação
* Um Data Feed de cupom opcional para incentivos de recuperação

Este guia foca na configuração do OneSignal. Seu sistema de reservas e backend podem ser implementados em qualquer linguagem ou framework.

### Fluxo de configuração

1. Seu app rastreia um [evento personalizado](./custom-events) `booking_started`.
2. Isso faz o usuário entrar em uma Journey.
3. A Journey aguarda um evento `booking_complete` e se não recebido a tempo, envia lembretes de acompanhamento.
4. Se a reserva for concluída, o OneSignal chama um Data Feed de reserva no momento do envio e envia um email de confirmação com os últimos detalhes da reserva.
5. Se a reserva não for concluída dentro da janela de espera, a Journey segue o caminho de expiração e envia um email de recuperação.

***

## Configuração

### Pré-requisitos

Antes de começar, certifique-se de ter:

* Um app OneSignal com o canal de [**Email**](./email-setup) habilitado
* Um endpoint backend que possa retornar dados de reserva e/ou cupom como JSON
* Um identificador de usuário estável compartilhado entre seu app, backend e [ID Externo](./users#external-id) do OneSignal
* Acesso a [Eventos Personalizados](./custom-events)

### 1. Rastrear eventos de reserva

Rastreie os seguintes Eventos Personalizados. Estes podem vir do seu app (usando nosso SDK) ou do seu backend (usando nossa API REST).

**Nomes dos eventos:**

* `booking_started` — quando o usuário inicia o fluxo de reserva
* `booking_complete` — quando a reserva é concluída com sucesso

<Tabs>
  <Tab title="App - Mobile e Web">
    Use o método `trackEvent()` em nosso [SDK Mobile](./mobile-sdk-reference) e/ou [SDK Web](./web-sdk-reference) para enviar eventos personalizados diretamente do seu app/website.

    ```js Exemplo theme={null}
    OneSignal.User.trackEvent("booking_started");
    OneSignal.User.trackEvent("booking_complete");
    ```
  </Tab>

  <Tab title="Lado do Servidor">
    Se você está rastreando eventos do seu backend, use a [API de Criar Eventos Personalizados](/reference/create-custom-events) para enviar eventos ao OneSignal.

    ```bash theme={null}
    curl --request POST \
      --url https://api.onesignal.com/apps/{app_id}/custom_events \
      --header 'Authorization: Key YOUR_APP_API_KEY' \
      --header 'Content-Type: application/json' \
      --data '{
        "events": [
          {
            "name": "booking_started",
            "external_id": "user123",
            "properties": {}
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

<Note>
  Use a mesma identidade de usuário ao rastrear eventos e ao retornar dados do seu backend. IDs incompatíveis são a causa mais comum de personalização ausente.
</Note>

### 2. Criar aliases de Data Feed

No OneSignal, vá para **Configurações > Data Feeds** e crie os seguintes aliases.

**Data Feed de Reserva:**
Use este feed para obter os últimos detalhes da reserva no momento do envio.

* **Alias:** `booking_data`
* **Método:** GET
* **URL:**

```liquid Exemplo de endpoint theme={null}
https://your-domain.com/datafeed/booking?user_id={{subscription.external_id}}
```

Exemplo de resposta:

```json JSON theme={null}
{
  "first_name": "Sam",
  "last_booking": {
    "service_type": "Consulta",
    "booking_date": "22 de Janeiro de 2026",
    "booking_time": "14:00",
    "price": 45
  }
}
```

**Data Feed de Cupom (opcional):**

Use este feed opcional se quiser incluir um código de cupom no seu email de recuperação.

* **Alias:** `coupon`
* **Método:** GET
* **URL:**

```liquid Exemplo de endpoint theme={null}
https://your-domain.com/datafeed/coupon?user_id={{subscription.external_id}}
```

Exemplo de resposta:

```json JSON theme={null}
{
  "first_name": "Sam",
  "code": "PROMO8F3K2",
  "discount_text": "10%",
  "expires_in_hours": 2,
  "deep_link": "https://your-domain.com/checkout?coupon=PROMO8F3K2"
}
```

<Warning>
  Proteja seus endpoints de Data Feed. Em produção, envie uma chave API nos headers da requisição (por exemplo `x-api-key`) e configure esse header em **Configurações > Data Feeds** em vez de incorporar segredos na URL.
</Warning>

### 3. Criar templates de email

#### Email de confirmação de reserva:

**Assunto:**

```text theme={null}
Seus detalhes de reserva
```

**Corpo:**

```liquid theme={null}
Olá {{ data_feed.booking_data.first_name | default: "cliente" }},

Obrigado pela sua reserva! Aqui estão os detalhes do seu agendamento:

Serviço: {{ data_feed.booking_data.last_booking.service_type }}
Data: {{ data_feed.booking_data.last_booking.booking_date }}
Horário: {{ data_feed.booking_data.last_booking.booking_time }}
Preço: R$ {{ data_feed.booking_data.last_booking.price }}

Estamos ansiosos para vê-lo!
```

#### Email de recuperação de reserva

**Assunto:**

```text theme={null}
Complete sua reserva e economize
```

**Corpo:**

<Tabs>
  <Tab title="Usando um Data Feed de Cupom">
    ```liquid theme={null}
    Olá {{ data_feed.coupon.first_name | default: "cliente" }},

    Finalize sua reserva nas próximas {{ data_feed.coupon.expires_in_hours }} horas e economize
    {{ data_feed.coupon.discount_text }} com este código:

    {{ data_feed.coupon.code }}

    Use aqui:
    {{ data_feed.coupon.deep_link }}
    ```
  </Tab>

  <Tab title="Sem um Data Feed de Cupom">
    ```text theme={null}
    Olá, 

    Você ainda não completou sua reserva! 

    Complete agora para economizar no seu próximo agendamento.

    Use este link para completar sua reserva:
    [Inserir deep link aqui]
    ```
  </Tab>
</Tabs>

<Note>
  Sempre inclua filtros `default` no Liquid para prevenir conteúdo em branco se um campo do Data Feed estiver faltando.
</Note>

### 4. Construir a Journey

1. No OneSignal, vá para **Mensagens > Journeys > Criar Journey**

2. Configure o **Gatilho de Entrada** como:
   * **Evento Personalizado:** `booking_started`

3. Adicione um passo **Aguardar Até**:
   * **Condição:** Evento Personalizado ocorre
   * **Nome do evento:** `booking_complete`
   * **Tempo máximo de espera:** 10 minutos
   * Habilite o caminho de expiração

4. Configure as ramificações:
   * **Concluído:** Enviar email de confirmação de reserva
     * **Data Feed:** `booking_data`
   * **Expirado:** Enviar email de recuperação
     * **Data Feed:** `coupon`

<Info>
  A ramificação de expiração permite que você trate o abandono sem lógica adicional no seu app. Veja:

  * [Configurações de Journey](./journeys-settings) - para detalhes sobre regras de entrada e saída de Eventos Personalizados
  * [Ações de Journeys](./journeys-actions) - para detalhes sobre passos Aguardar Até e ramificações de expiração
</Info>

### 5. Testar e verificar

#### Verificar eventos

Dispare os eventos personalizados do seu app ou backend e confirme.

No OneSignal, vá para **Analytics > Eventos Personalizados** e confirme que você vê:

* Eventos `booking_started` aparecem para o seu ID Externo
* Eventos `booking_complete` aparecem para o seu ID Externo

#### Verificar Data Feeds

Chame manualmente seus endpoints de Data Feed usando um ID de usuário conhecido e confirme:

* Uma resposta 200 é retornada
* Todos os campos esperados estão presentes

#### Verificar emails

Envie mensagens de teste do editor de Journey e confirme:

* Emails de reserva contêm detalhes reais da reserva
* Emails de recuperação contêm um cupom válido
* Nenhuma variável Liquid renderiza vazia

<Check>
  Se a personalização estiver faltando, confirme que o ID do usuário na requisição do Data Feed corresponde ao usuário que disparou a Journey.
</Check>

## Exemplo: Implementação de Data Feed

<Accordion title="Exemplos de endpoints de Data Feed Node.js">
  Este exemplo mostra uma implementação Express mínima para Data Feeds de confirmação de reserva e recuperação. Sua linguagem backend, framework e fonte de dados podem diferir contanto que a forma da resposta JSON corresponda aos seus templates de email.

  ### Exemplo de Data Feed de Reserva

  ```js theme={null}
  import express from "express";

  const app = express();

  function dataFeedAuth(req, res, next) {
    if (req.headers["x-api-key"] !== process.env.DATAFEED_API_KEY) {
      return res.status(401).json({ error: "Unauthorized" });
    }
    next();
  }

  app.get("/datafeed/booking", dataFeedAuth, async (req, res) => {
    const { user_id } = req.query;

    if (!user_id) {
      return res.status(400).json({ error: "Missing user_id" });
    }

    const booking = await getLatestBookingForUser(user_id);

    if (!booking) {
      return res.status(404).json({ error: "No booking found" });
    }

    res.json({
      first_name: booking.first_name,
      last_booking: {
        service_type: booking.service_type,
        booking_date: booking.booking_date,
        booking_time: booking.booking_time,
        price: booking.price
      }
    });
  });
  ```

  ### Exemplo de Data Feed de Cupom

  ```js theme={null}
  app.get("/datafeed/coupon", dataFeedAuth, async (req, res) => {
    const { user_id } = req.query;

    if (!user_id) {
      return res.status(400).json({ error: "Missing user_id" });
    }

    const coupon = await generateCouponForUser(user_id);

    res.json({
      first_name: coupon.first_name,
      code: coupon.code,
      discount_text: coupon.discount_text,
      expires_in_hours: coupon.expires_in_hours,
      deep_link: coupon.deep_link
    });
  });
  ```

  ### Diretrizes de implementação

  * Mantenha as respostas rápidas (Data Feeds são chamados no momento do envio)
  * Sempre retorne uma estrutura JSON previsível
  * Use 404 quando não existirem dados
  * Proteja endpoints com uma chave API enviada via headers de requisição
</Accordion>

## Problemas comuns

### Email mostra valores vazios

* Data Feed retornou 404
* Nomes de campos mudaram na resposta JSON
* Incompatibilidade de identidade do usuário

### Journey não se ramifica

* Evento `booking_complete` não rastreado
* Incompatibilidade de nome do evento (sensível a maiúsculas)
* Evento ocorre fora da janela de espera

### Data Feed retorna 401 ou 403

* Chave API ausente ou inválida
* Header não configurado nas configurações do Data Feed

## Próximos passos

* Adicionar propriedades de evento (tipo de serviço, preço) para condições de Journey mais avançadas
* Adicionar passos de recuperação adicionais como lembretes push ou SMS
* Usar regras de saída de Journey para prevenir mensagens de recuperação repetidas

***
