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

# Eventos e operações

> Liste e consulte periodicamente o histórico de eventos, receba eventos em tempo real, reenvie eventos e aguarde operações assíncronas.

Todo evento de webhook também fica armazenado no histórico de eventos. Leia
esse histórico para preencher lacunas, reconciliar dados ou receber eventos sem
um endpoint público. As operações acompanham trabalhos que terminam depois que
a solicitação retorna, como o envio de uma campanha.

| Tarefa | Permissão |
| - | - |
| Listar e ler eventos | `events:read` |
| Reenviar um evento para um webhook | `events:replay` |
| Receber eventos em stream (beta) | `events:listen` |
| Ler e aguardar operações | `operations:read` |
| Cancelar uma operação | `operations:cancel` |

Um cliente de projeto vê o próprio projeto. Um cliente de equipe vê os eventos
da equipe e os eventos de todos os projetos.

## Liste eventos

```typescript theme={null}
for await (const event of await project.events.list({ type: "message.received", limit: 100 })) {
  console.log(event.id, event.type, event.createdAt, event.payloadAvailability);
}
```

Filtre com `type`, `since` e `until`. Para ler um evento com o corpo, peça a
carga:

```typescript theme={null}
const event = await project.events.retrieve("<event-id>", { includePayload: true });

if (event.data.payload) {
  const body = JSON.parse(atob(event.data.payload.data));
  console.log(body);
}
```

O corpo é JSON codificado em base64. `payloadAvailability` informa quando um
corpo não está disponível, por exemplo depois que ele expirou. Veja
[Histórico de eventos](/api/events).

## Consulte novos eventos periodicamente

`listIndexed` retorna os eventos na ordem em que a Polymorfa os armazenou, não
na ordem em que aconteceram. Use-o para consultas periódicas: um evento
armazenado com atraso, como uma mensagem recebida depois de uma reconexão,
ainda aparece depois do offset que você salvou. Comece de uma linha de base e
depois consulte a partir do offset salvo:

```typescript theme={null}
// Baseline: start after everything stored so far.
let offset = (await project.events.listIndexed({ afterOffset: "0", limit: 1 })).page.highWatermark;

async function poll() {
  const result = await project.events.listIndexed({ afterOffset: offset, limit: 100 });
  for (const event of result.items) console.log(event.id, event.type);

  offset = result.page.hasMore && result.page.nextOffset
    ? result.page.nextOffset
    : result.page.highWatermark;
  return result.page.hasMore;
}

while (await poll()) {}
```

Enquanto `hasMore` for `true`, continue a partir de `nextOffset`. Quando a
página se esgotar, salve `highWatermark` e passe esse valor na próxima
consulta. Offsets são strings decimais. Mantenha-os como strings.

## Receba eventos em tempo real

> [!NOTE]
>
> Os streams de eventos estão em beta. Um proprietário ou administrador da equipe
> entra no beta pela linha dele na página **Chaves de API** do projeto, no
> Console. Até a equipe entrar, o stream lança `PolymorfaAuthorizationError` com
> o código `feature_unavailable`. Veja [Streams de eventos](/api/event-streams).

```typescript theme={null}
const controller = new AbortController();
process.once("SIGINT", () => controller.abort());

for await (const item of project.events.stream({
  types: ["message.*", "session.status"],
  signal: controller.signal,
})) {
  console.log(item.event.id, item.event.type, item.webhook?.payload);
  // Save item.cursor after you process the event.
}
```

`stream()` se reconecta depois de uma queda de conexão e continua a partir do
último evento que entregou. Cada item tem:

* `event`: o registro do evento, com os mesmos campos de `events.retrieve`.
* `webhook`: o corpo do webhook, ou `null` quando o corpo não foi mantido.
* `cursor`: a posição depois deste evento.

Para continuar depois de um reinício, passe o cursor salvo como `since`. Passe
`onGap` para saber quando eventos expiraram antes de você continuar. Abortar o
signal ou sair do loop fecha o stream. Um cliente de equipe precisa passar
`projectId`.

Execute streams apenas no seu servidor. Tokens de cliente não podem abri-los.

## Reenvie um evento

Envie de novo um evento armazenado para um endpoint de webhook:

```typescript theme={null}
const replay = await project.events.replay(
  "<event-id>",
  { webhookId: "<webhook-id>" },
  { idempotencyKey: crypto.randomUUID() },
);

console.log(replay.data.deliveryId, replay.data.operationId);
```

Apenas o endpoint que você indicar recebe o evento. Um evento pode ser
reenviado até o horário `replayableUntil` dele.

## Aguarde uma operação

Métodos que iniciam trabalho em segundo plano retornam um ID de operação.
Aguarde até que ela termine:

```typescript theme={null}
const operation = await platform.operations.wait("<operation-id>", {
  maxWaitMs: 10 * 60_000,
});

if (operation.data.status !== "succeeded") {
  console.error(operation.data.status, operation.data.error?.code);
}
```

`wait` retorna quando a operação tem sucesso, falha ou é cancelada, ou quando
`maxWaitMs` termina (5 minutos por padrão). Em todos os casos, ele retorna o
estado mais recente, então sempre verifique `status`.

## Encontre e cancele operações

```typescript theme={null}
for await (const running of await platform.operations.list({ status: "running" })) {
  console.log(running.id, running.kind, running.status);

  if (running.capabilities.cancellable) {
    await platform.operations.cancel(running.id);
  }
}
```

`get(id)` lê uma operação. Passe `{ wait: 30 }` para manter a solicitação
aberta por até 30 segundos até a operação mudar. `listTransitions(id)` lista as
mudanças de estado dela. O cancelamento só funciona enquanto
`capabilities.cancellable` for `true`. Veja [Operações](/api/operations).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.