Webhooks — Eventos ASAAS
O fast_deliv recebe notificacoes do ASAAS quando transferencias Pix sao processadas. Voce pode expor um endpoint proprio para receber esses eventos e reagir a eles no seu sistema.
Configuracao
URL do webhook
Este endpoint nao requer JWT. A autenticidade e verificada via assinatura HMAC-SHA256.
Header de autenticidade
| Header | Descricao |
|---|---|
asaas-signature |
HMAC-SHA256 do body com o ASAAS_WEBHOOK_SECRET |
Seguranca
Sempre valide a assinatura antes de processar o payload. Nunca confie apenas no IP de origem.
Validando a assinatura
import hashlib
import hmac
from fastapi import Request, HTTPException
ASAAS_WEBHOOK_SECRET = "seu_webhook_secret"
async def verify_asaas_signature(request: Request) -> bytes:
body = await request.body()
signature = request.headers.get("asaas-signature", "")
expected = hmac.new(
ASAAS_WEBHOOK_SECRET.encode(),
body,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, signature):
raise HTTPException(status_code=401, detail="Assinatura invalida")
return body
import crypto from "crypto";
const ASAAS_WEBHOOK_SECRET = process.env.ASAAS_WEBHOOK_SECRET;
function verifySignature(rawBody, signature) {
const expected = crypto
.createHmac("sha256", ASAAS_WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
// Express handler
app.post("/webhooks/asaas", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["asaas-signature"];
if (!verifySignature(req.body, sig)) {
return res.status(401).json({ error: "Assinatura invalida" });
}
const event = JSON.parse(req.body.toString());
handleEvent(event);
res.status(200).json({ received: true });
});
require 'openssl'
ASAAS_WEBHOOK_SECRET = ENV['ASAAS_WEBHOOK_SECRET']
def verify_signature(raw_body, signature)
expected = OpenSSL::HMAC.hexdigest('SHA256', ASAAS_WEBHOOK_SECRET, raw_body)
ActiveSupport::SecurityUtils.secure_compare(expected, signature)
# Ou sem ActiveSupport:
# expected.bytes.zip(signature.bytes).all? { |a, b| a == b }
end
Eventos
TRANSFER_DONE / TRANSFER_APPROVED
Transferencia Pix concluida com sucesso. O withdrawal.status e atualizado para completed.
{
"event": "TRANSFER_DONE",
"payment": {
"id": "tra_xxxxxxxxxxxx",
"status": "DONE",
"value": 50.00,
"description": "Saque fast_deliv — motorista Carlos Silva",
"dateCreated": "2026-05-19",
"confirmedDate": "2026-05-19"
}
}
TRANSFER_FAILED / TRANSFER_CANCELLED
Transferencia falhou ou foi cancelada. O withdrawal.status e atualizado para failed.
{
"event": "TRANSFER_FAILED",
"payment": {
"id": "tra_xxxxxxxxxxxx",
"status": "FAILED",
"value": 50.00,
"description": "Saque fast_deliv — motorista Carlos Silva",
"failReason": "Chave Pix invalida ou inexistente",
"dateCreated": "2026-05-19"
}
}
Resposta esperada
O endpoint deve retornar 200 OK em menos de 5 segundos. Qualquer outro status fara o ASAAS tentar reenviar.
Processamento assincrono
Se o processamento for demorado, responda 200 imediatamente e enfileire o evento em background (Celery, RQ, etc.).
Tabela de eventos
| Evento | Descricao | Acao no sistema |
|---|---|---|
TRANSFER_DONE |
Saque concluido | withdrawal.status = completed |
TRANSFER_APPROVED |
Saque aprovado pelo banco | Idem (alias) |
TRANSFER_FAILED |
Saque falhou | withdrawal.status = failed, saldo revertido |
TRANSFER_CANCELLED |
Saque cancelado | Idem ao FAILED |