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

# Webhooks

> Os eventos grant.revoked e ping, assinados no esquema Standard Webhooks.

O MyPilotIndex informa um parceiro sobre os grants dele por webhook. Existem dois eventos: `grant.revoked`, quando um grant termina, e `ping`, quando você pede um teste.

O MyPilotIndex define a URL do seu webhook (só https) e o secret de assinatura dela quando aprova você. O secret começa com `whsec_` e é mostrado uma única vez.

## Entrega

Cada evento é um `POST` do evento em JSON (`Content-Type: application/json`). Responda com qualquer `2xx` em até 10 segundos.

Cabeçalhos, no esquema Standard Webhooks:

| Cabeçalho | Conteúdo |
| - | - |
| `webhook-id` | O id do evento, o mesmo em todas as tentativas. Use-o para descartar duplicatas. |
| `webhook-timestamp` | Segundos Unix inteiros do momento em que esta tentativa foi assinada. |
| `webhook-signature` | `v1,` seguido do HMAC-SHA256 em base64 de `<webhook-id>.<webhook-timestamp>.<body>`. |

## Verificando a assinatura

A chave é o conteúdo em base64 do seu secret depois do prefixo `whsec_`. Calcule o HMAC sobre os bytes exatos que você recebeu, não sobre um corpo serializado de novo, compare em tempo constante e recuse um timestamp que esteja a mais de cinco minutos do seu relógio.

```js theme={null}
const crypto = require('node:crypto')

function verify(secret, id, timestamp, rawBody, signatureHeader) {
  const age = Math.abs(Date.now() / 1000 - Number(timestamp))
  if (!Number.isFinite(age) || age > 300) return false // more than five minutes from our clock
  const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64')
  const expected = crypto.createHmac('sha256', key)
    .update(`${id}.${timestamp}.${rawBody}`).digest('base64')
  const a = Buffer.from(`v1,${expected}`)
  return signatureHeader.split(' ').some(candidate => {
    const b = Buffer.from(candidate)
    return a.length === b.length && crypto.timingSafeEqual(a, b)
  })
}
```

## grant.revoked

```json theme={null}
{
  "type": "grant.revoked",
  "id": "evt_3b1f6c0e9a2d4f7b8c5e1a2b3c4d5e6f",
  "created_at": "2026-11-05T09:30:00Z",
  "data": {
    "grant_id": "6f1c2a9e-3b7d-4c51-9e2a-0d4b8f6a1c33",
    "pilot_id": "2d9b7c1e-8f4a-4e3b-a6d5-91c0f2e7b844",
    "reason": "pilot"
  }
}
```

`reason` é `pilot` (o piloto desconectou você em Configurações), `operator` (o MyPilotIndex revogou o grant) ou `account_deleted` (o piloto apagou a conta, então o grant não aparece mais em nenhuma lista).

Quando receber esse evento, apague o que você guarda do MyPilotIndex sobre esse piloto, como o acordo de dados exige. A partir desse momento, toda chamada que indica o grant responde `404`.

## Novas tentativas

Um `5xx`, um `408`, um `429`, um redirecionamento (nunca seguido), um timeout ou uma falha de conexão gera novas tentativas com intervalos crescentes por cerca de um dia, doze tentativas no total, com o mesmo `webhook-id` e um timestamp e uma assinatura novos. Um `4xx` que não seja `408` nem `429` é tratado como recusa e não gera nova tentativa.

A exceção é o `grant.revoked` com o motivo `account_deleted`: o grant dele sai de todas as listas junto com a conta, então não pode ser reconciliado depois. Ele é reenviado dentro da mesma janela diante de qualquer resposta que não seja `2xx`, inclusive um `4xx`. Confirme o recebimento com um `2xx` assim que tiver processado o evento, mesmo que você não guarde nada sobre esse piloto.

Se você perdeu outros eventos, reconcilie com `GET /v1/partner/grants?status=revoked&changed_since=<time>`.

## Testes

`POST /v1/partner/webhooks/test` coloca na fila um `ping` assinado para a URL do seu webhook e responde `202` antes da entrega. O evento `ping` tem um objeto `data` vazio. Se não houver URL de webhook (https) ou secret registrados, a resposta é `409` com o motivo `webhook_not_configured`.


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