Webhooks avisam o seu sistema quando algo acontece no Astro, como um pagamento aprovado ou uma assinatura cancelada.
Cadastre um endpoint
Em Desenvolvedores → Webhooks, informe a URL HTTPS que vai receber os eventos e escolha quais eventos assinar. Guarde o segredo de assinatura exibido no cadastro: ele é usado para validar cada entrega.
Eventos
| Grupo | Eventos |
|---|---|
| Pagamentos | payment.approved, payment.failed, payment.canceled, payment.refunded, payment.partially_refunded, payment.disputed |
| Assinaturas | subscription.created, subscription.activated, subscription.renewed, subscription.past_due, subscription.canceled, subscription.paused, subscription.resumed |
| Faturas | invoice.paid, invoice.payment_failed |
Headers da entrega
Cada entrega é um POST com corpo JSON e estes headers:
| Header | Conteúdo |
|---|---|
Astro-Event-Id |
identificador único do evento |
Astro-Event-Type |
tipo do evento, como payment.approved |
Astro-Timestamp |
momento do envio, em segundos (Unix) |
Astro-Signature |
HMAC-SHA256 em hexadecimal |
Valide a assinatura
A assinatura é o HMAC-SHA256 do texto timestamp + "." + corpo bruto, usando o segredo do endpoint. Calcule com o corpo exatamente como recebido, antes de qualquer parse:
import { createHmac, timingSafeEqual } from "node:crypto";
export function isValidAstroWebhook(rawBody: string, headers: Headers, secret: string) {
const timestamp = headers.get("astro-timestamp") ?? "";
const received = headers.get("astro-signature") ?? "";
const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
return (
received.length === expected.length &&
timingSafeEqual(Buffer.from(received), Buffer.from(expected))
);
}
Importante: use o
Astro-Event-Idpara ignorar entregas repetidas. O mesmo evento pode chegar mais de uma vez.
Corpo da entrega
Além do evento, cada entrega traz o contexto para você agir sem chamar a API:
{
"paymentId": "pay_...",
"status": "approved",
"externalReference": "user_123",
"metadata": { "plano": "pro" },
"customer": {
"id": "cus_...",
"email": "cliente@exemplo.com",
"name": "Cliente",
"externalReference": null
},
"payment": {
"id": "pay_...",
"status": "approved",
"method": "pix",
"amountMinor": 9900,
"capturedMinor": 9900,
"refundedMinor": 0,
"currency": "BRL"
},
"subscription": {
"id": "sub_...",
"status": "active",
"currentPeriodEndsAt": "2026-12-02T00:00:00Z"
}
}
Valores estão em centavos. payment.disputed indica chargeback: revogue o acesso até a disputa
terminar.
Teste sem fazer uma compra
Na lista de endpoints, use Enviar evento de teste. O Astro envia um webhook.test assinado,
com o mesmo formato acima, e o resultado aparece em Logs → Webhooks.
Tentativas e reenvio
Responda com um status 2xx para confirmar o recebimento. Se a entrega falhar, o Astro tenta de novo até sete vezes: imediatamente, depois de 1 min, 5 min, 15 min, 1 h, 6 h e 24 h. Esgotadas as tentativas, a entrega fica marcada como falha e pode ser reenviada manualmente pelo painel.