Webhooks
Los webhooks te permiten recibir notificaciones en tiempo real cuando ocurren eventos importantes en tu cuenta, como cuando una factura es aceptada o rechazada por la AEAT.
Cuando el estado de una factura cambia, Certifactu envía una petición HTTP POST a tu endpoint configurado.
Crear Webhook
Configura un endpoint en tu servidor para recibir notificaciones. Puedes suscribirte a eventos específicos o recibir todos.
/invoices/webhooksRegistra un nuevo webhook
Parámetros
url string requeridoURL de tu servidor que recibirá las notificaciones. Debe ser HTTPS.
secret string opcionalSecreto para firmar los payloads y verificar autenticidad. Muy recomendado.
events array opcionalLista de eventos a los que suscribirse. Si se omite, recibirás todos.
Por defecto: ["status_changed"]
curl -X POST https://api.certifactu.com/api/v1/invoices/webhooks \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"url": "https://mi-servidor.com/webhooks/certifactu",
"secret": "mi_secreto_super_seguro",
"events": ["status_changed", "rejected"]
}'Eventos Disponibles
Puedes suscribirte a los siguientes eventos:
status_changed Se dispara cuando cambia el estado de cualquier factura.
accepted Cuando una factura es aceptada por la AEAT.
rejected Cuando una factura es rechazada (requiere subsanación).
cancelled Cuando una factura es anulada por el usuario.
Formato del Payload
Tu servidor recibirá una petición POST con el siguiente formato JSON:
{
"event": "status_changed",
"timestamp": "2024-01-30T12:00:00Z",
"webhook_id": "wh_abc123def456",
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"series": "F2024",
"number": "001",
"old_status": "QUEUED",
"new_status": "ACCEPTED",
"aeat_csv": "CSV123456789ABCDEF"
}
}Estados de factura
Verificación de Firma
Si configuraste un secret, incluiremos una cabecera con la firma HMAC SHA-256 del
cuerpo de la petición. Siempre verifica esta firma antes de procesar el webhook.
X-Webhook-Signature: sha256=f4b7c8d9e0a1b2c3d4e5f6...Cómo verificar la firma
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
"""Verifica la firma del webhook."""
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
# Extraer hash de la cabecera "sha256=..."
received = signature.replace("sha256=", "")
return hmac.compare_digest(expected, received)
# En tu endpoint Flask/FastAPI:
@app.post("/webhooks/certifactu")
async def handle_webhook(request: Request):
payload = await request.body()
signature = request.headers.get("X-Webhook-Signature", "")
if not verify_webhook(payload, signature, WEBHOOK_SECRET):
raise HTTPException(status_code=401, detail="Invalid signature")
data = json.loads(payload)
# Procesar el webhook...