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

# Receber eventos

> Formato do envelope, headers enviados, validação do token, respostas esperadas e novas tentativas.

A cada evento assinado, o Gestio envia uma requisição `POST` para a URL do endpoint com o corpo JSON (envelope) e headers de identificação.

## Requisição enviada

```http theme={null}
POST /webhooks/gestio HTTP/1.1
Host: integracao.suaempresa.com.br
Content-Type: application/json; charset=utf-8
User-Agent: Gestio-Webhook/1.0
X-Gestio-Webhook-Id: 3f2b8c1e-6a4d-4f0b-9c2e-1d7a5b8e9f10
X-Gestio-Event: compras.pedido-de-compra.processado
X-Gestio-Webhook-Token: gwhtok_...

{"id":"3f2b8c1e-6a4d-4f0b-9c2e-1d7a5b8e9f10","tipo":"compras.pedido-de-compra.processado","versao":1,"ocorridoEm":"2026-11-03T14:30:00Z","dados":{...}}
```

### Headers

| Header | Descrição |
| - | - |
| `X-Gestio-Webhook-Id` | Identificador do log (`idEntrega`). É o mesmo valor do campo `id` do envelope e se mantém nas novas tentativas e nos reenvios. |
| `X-Gestio-Event` | Código do evento, igual ao campo `tipo` do envelope. |
| `X-Gestio-Webhook-Token` | Token do endpoint, para você validar a origem da chamada. |
| `User-Agent` | Sempre `Gestio-Webhook/1.0`. |
| `Content-Type` | `application/json`. |

### Envelope

**id** `string (uuid)` *required*

Identificador do log. Use para identificar duplicidades.

**tipo** `string` *required*

Código do evento, por exemplo `compras.pedido-de-compra.processado`.

**versao** `integer` *required*

Versão do formato do envelope. Atualmente `1`.

**ocorridoEm** `string (date-time)` *required*

Data e hora em UTC, em ISO 8601 (ex.: `2026-11-03T14:30:00Z`).

**teste** `boolean`

Presente e igual a `true` **somente** em envios de teste. Eventos reais não têm este campo.

**dados** `object` *required*

Dados do evento. O conteúdo depende do `tipo`; veja o [catálogo de eventos](https://docs.gestio.com.br/pages/webhooks/eventos.md).

***

## Validar o token

Compare o header `X-Gestio-Webhook-Token` com o token que você guardou no cadastro do endpoint. Se for diferente ou estiver ausente, responda `401` e não processe o evento.

```javascript Node.js (Express) theme={null}
const crypto = require('crypto');
const express = require('express');
const app = express();

const TOKEN = process.env.GESTIO_WEBHOOK_TOKEN;

function tokenValido(recebido) {
  if (!recebido) return false;
  const a = Buffer.from(recebido);
  const b = Buffer.from(TOKEN);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post('/webhooks/gestio', express.json(), async (req, res) => {
  if (!tokenValido(req.get('X-Gestio-Webhook-Token'))) {
    return res.sendStatus(401);
  }

  const envelope = req.body;
  if (envelope.teste) {
    console.log('Envio de teste recebido', envelope.id);
    return res.sendStatus(200);
  }

  // Grave o envelope (ou enfileire) e processe de forma assíncrona
  await filaInterna.publicar(envelope);
  res.sendStatus(200);
});
```

```csharp C# (ASP.NET Core) theme={null}
app.MapPost("/webhooks/gestio", async (HttpRequest request, IConfiguration configuration) =>
{
    var tokenEsperado = configuration["Gestio:WebhookToken"];
    var tokenRecebido = request.Headers["X-Gestio-Webhook-Token"].ToString();

    var tokenValido = CryptographicOperations.FixedTimeEquals(
        Encoding.UTF8.GetBytes(tokenRecebido),
        Encoding.UTF8.GetBytes(tokenEsperado));

    if (!tokenValido)
    {
        return Results.Unauthorized();
    }

    var envelope = await request.ReadFromJsonAsync<JsonElement>();
    if (envelope.TryGetProperty("teste", out var teste) && teste.GetBoolean())
    {
        return Results.Ok();
    }

    // Grave o envelope (ou enfileire) e processe de forma assíncrona
    return Results.Ok();
});
```

> [!WARNING]
>
> O token trafega no header da requisição, por isso o Gestio só envia webhooks para URLs **HTTPS**. Nunca registre o token em logs e guarde-o em um cofre de segredos.

***

## Responder ao evento

| Resposta do seu sistema | Resultado no Gestio |
| - | - |
| HTTP `2xx` | Log fica `Entregue`. O contador de falhas do endpoint volta a `0`. |
| HTTP `5xx`, `408`, `429` ou tempo limite excedido | Falha temporária: nova tentativa automática. |
| Outros HTTP `4xx` (ex.: `400`, `401`, `404`) | Falha definitiva: o log vai para `Falha` sem novas tentativas. |
| Erro de conexão (TLS, conexão recusada) | Falha temporária: nova tentativa automática. |
| Host da URL passou a apontar para endereço não público | Falha definitiva, sem novas tentativas. |

Regras da chamada:

* **Tempo limite de 10 segundos.** Responda rápido: grave o evento e processe depois, de forma assíncrona.
* **Redirecionamentos não são seguidos.** Uma resposta `3xx` conta como falha definitiva; cadastre a URL final.
* O corpo da sua resposta é ignorado e não é gravado.

### Novas tentativas

Falhas temporárias são repetidas com intervalos crescentes, num total de **6 tentativas** (o envio inicial e mais 5):

| Tentativa | Intervalo após a anterior |
| - | - |
| 1ª | envio imediato |
| 2ª | 1 minuto |
| 3ª | 5 minutos |
| 4ª | 30 minutos |
| 5ª | 2 horas |
| 6ª | 6 horas |

Se todas falharem, o log fica com a situação `Falha` e pode ser [reenviado manualmente](https://docs.gestio.com.br/pages/webhooks/testar-e-reenviar.md#reenviar-um-log).

> [!NOTE]
>
> Cada tentativa com falha incrementa o contador de falhas do endpoint. Com **20 falhas seguidas**, o endpoint é desativado automaticamente. Veja [Ativar e desativar](https://docs.gestio.com.br/pages/webhooks/gerenciar-endpoints.md#desativação-automática).

***

## Boas práticas

> [accordion] Trate duplicidades pelo id
>
> O envio é feito pelo menos uma vez. Guarde os `id` já processados e ignore os repetidos. Um mesmo pedido processado de novo no Gestio gera um log com **outro** `id`; para esse caso, use os dados do evento (por exemplo, `numeroDoPedido`) para decidir se deve atualizar o registro.

> [accordion] Responda primeiro, processe depois
>
> Grave o envelope e responda `200` antes de executar regras demoradas. O limite é de 10 segundos.

> [accordion] Ignore os envios de teste
>
> Envios de teste têm `teste: true` e dados fictícios. Responda `2xx` para confirmar a conectividade, mas não as processe como eventos reais.

> [accordion] Ignore campos desconhecidos
>
> Novos campos podem ser adicionados a `dados` sem mudar a `versao` do envelope. Seu sistema não deve falhar ao receber campos que não conhece.

> [accordion] Não dependa da ordem
>
> Eventos podem chegar fora de ordem, principalmente após novas tentativas. Use `ocorridoEm` quando a ordem importar.


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