> For the complete documentation index, see [llms.txt](https://docs.skail.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.skail.dev/aprender/exemplos-completos/fluxo-de-aprovacao-com-timeout.md).

# Fluxo de aprovação (com timeout)

Muitos sistemas precisam lidar com algo simples, mas chato de implementar:

* enviar um e-mail
* esperar o usuário responder
* e seguir o fluxo com base nisso
* ou tomar uma ação automática se ele não responder

No legado, isso normalmente vira uma mistura de:

* tabela de controle
* job rodando de tempos em tempos
* lógica de timeout manual
* retries espalhados

Com o skail, isso vira um código direto simples.

### Esperando aprovação com prazo

Imagine um fluxo de aprovação simples:

1. você envia um e-mail com um link
2. espera o usuário responder
3. se ele aprovar → segue o fluxo
4. se ele rejeitar → notifica a rejeição
5. se não responder em 72h → expira

No skail, isso vira uma função linear:

```csharp
[SkailFunction]
public async SkailTask WaitForApprovalWithTimeout(Guid approvalId)
{
    await SendApprovalEmail(approvalId);

    var approvalTask = SkailTask.WaitForEvent<ApprovalResponse>("EVT_APPROVAL", approvalId.ToString());
    var timeoutTask = SkailTask.Delay(TimeSpan.FromHours(72));

    var result = await SkailTask.WhenAny(approvalTask, timeoutTask);

    if (result == timeoutTask)
    {
        await NotifyExpired(approvalId);
        return;
    }

    var response = await approvalTask;

    if (response.Approved)
        await NotifyApproved(approvalId);
    else
        await NotifyRejected(approvalId);
}

public record ApprovalResponse(bool Approved);
```

### O que está acontecendo aqui

O fluxo é simples de ler:<br>

1. envia o e-mail
2. espera duas coisas ao mesmo tempo:
   1. o usuário responder
   2. ou, o tempo expirar
3. segue baseado no que acontecer primeiro
4. se a resposta chegou, lê o payload: aprovado segue o fluxo, rejeitado notifica a rejeição

**Sem jobs, sem polling, sem tabela de controle, só código de regra de negócio.**

### Enviando o e-mail (sem mudar seu legado)

A chamada para enviar o e-mail continua sendo uma integração normal:

```csharp
[SkailCommand]
public async SkailTask SendApprovalEmail(Guid approvalId)
{
    var link = $"https://portal.company.com/approve/{approvalId}";
    await EmailService.SendAsync("Approval Required", $"Click here to approve: {link}");
}
```

Ou seja:

* você continua usando seus serviços atuais
* sem precisar reescrever nada

### Como o usuário responde

Quando o usuário clica no link, o endpoint que recebe o clique só precisa disparar o evento na [API HTTP de eventos do skail](/construir/api-http/post-api-v1-fire-eventname-instanceid.md). Pode ser o seu backend, um BFF, um webhook, qualquer sistema em qualquer linguagem:

```bash
curl -X POST "https://SEU_SKAIL_BASE_URL/api/v1/fire/EVT_APPROVAL/{approvalId}" \
  -H "Content-Type: application/json" \
  -H "skail-key: SUA_SKAIL_KEY" \
  -H "Skail-namespace: SEU_NAMESPACE" \
  -d '{ "Approved": true }'
```

O nome do evento (`EVT_APPROVAL`) e o identificador (`approvalId`) precisam ser exatamente os mesmos usados no `WaitForEvent`. É esse par que conecta quem dispara a quem está esperando. O corpo é desserializado em `ApprovalResponse`: com `{ "Approved": false }`, a função segue pelo ramo da rejeição.

E pronto: a execução continua de onde parou.

### Por que isso é relevante

No modelo tradicional, esse tipo de fluxo costuma ser difícil de manter:

* estado espalhado
* lógica de timeout manual
* difícil de entender o que está acontecendo

Aqui, tudo fica explícito:

* **o fluxo está em um único lugar**
* o estado é controlado automaticamente
* o tempo não depende de job rodando

### E se demorar dias?

Não importa.

A execução pode ficar “pausada” por horas ou dias, sem consumir recurso, e continua exatamente de onde parou quando o evento chega, com todas as variáveis e contexto (como se nunca tivesse parado).

### Resultado

Você transforma algo que normalmente é:

* complexo
* frágil
* difícil de debugar

...em um fluxo simples de ler e manter.

Sem falar na facilidade de depurar com o Time Travel Debug, como qualquer outro código skail.
