Webhooks
hook = client.webhooks.create("https://example.com/hook", events=["artifact.updated", "job.completed"])secret = hook["secret"] # この応答でのみ取得可能
# 受信側from d2b.client import _Webhooksok = _Webhooks.verify_delivery(secret, request.headers, raw_body) # firma + hora de envío (por defecto: dentro de 5 min)- Firma:
X-D2B-Signature-V2: sha256=<hex>= HMAC-SHA256(secret,"{X-D2B-Delivery}.{X-D2B-Timestamp}." + raw_body).X-D2B-Timestampes la hora de envío de ese intento (segundos UNIX, renovada en cada reintento): rechaza las peticiones cuya antigüedad supere tu tolerancia (por ejemplo, 5 minutos) para frustrar repeticiones (replay).X-D2B-Deliveryes el id de la entrega (el mismo en cada reintento). Verifica sobre el body crudo (sin reserializar) - La firma anterior
X-D2B-Signature: sha256=<hex>= HMAC-SHA256(secret, raw_body) se sigue enviando. No incluye la hora de envío, así que no puede impedir una repetición - Eventos:
artifact.updated/artifact.deleted/artifact.stale/snapshot.committed/source.analyzed/source.materialized/conflict.created/version.branched/version.merged/job.completed - Historial de entregas:
GET /api/v1/me/webhooks/{id}/deliveries - Reintentos: las respuestas no 2xx y los fallos de conexión se reintentan hasta 14 veces con espera exponencial de 30 s a 1 h (unas 8 horas en total). Una entrega que sigue fallando permanece visible en
deliveries, pero no se reintenta más. Cada evento genera una entrega, pero un intento cuya respuesta nunca llegó se reintenta, así que la misma entrega (el mismoX-D2B-Delivery) puede llegarte más de una vez: procesa las entregas de forma idempotente, usandoX-D2B-Deliverycomo clave. Eltimestampdel payload es la hora del evento y no cambia en los reintentos
Para los procesos largos (como la ingesta de archivos grandes), lo recomendado es convertirlos en un job con async=true y esperar job.completed — sale más barato que un loop de polling y aguanta mejor los timeouts de los agentes.