Guides
Webhooks
Receive signed, retried upload verdict events from Safeput.
Safeput can deliver a terminal upload verdict to one HTTPS endpoint per project:
upload.cleanupload.rejectedupload.failedConfigure the URL and subscribed events from the dashboard. The signing secret is displayed only when the endpoint is created or its secret is rotated.
Event envelope
Each request is a JSON POST with an immutable event ID:
{ "id": "12c09ac1-dc57-4e4f-8b43-35f7a5fdf229", "type": "upload.clean", "api_version": "v1", "created_at": "2026-08-22T12:00:00.000Z", "data": { "upload": { "id": "7cc816f4-0e2e-4be0-9eaa-b9615a27ee52", "project_id": "47db67f6-8fbc-4c59-95eb-f5150e18d820", "status": "clean", "filename": "invoice.pdf", "verdict": { "result": "clean", "reason_code": null, "detected_type": "application/pdf" } } }}Use the event id as an idempotency key. Safeput uses at-least-once delivery,
so the same event can be received more than once.
Verify the signature
Webhook requests include:
Safeput-Event-Id: ...Safeput-Event-Type: upload.cleanSafeput-Timestamp: 1787400000Safeput-Signature: v1=<base64url-hmac>Calculate HMAC-SHA256 with the webhook signing secret over the exact string
<Safeput-Timestamp>.<raw request body>. Base64url-encode the digest without
padding, prepend v1=, and compare it in constant time. Reject stale timestamps
before processing the event.
Delivery behavior
Safeput accepts any 2xx response. Network errors, timeouts, 408, 429, and
5xx responses retry with increasing delays for up to eight attempts. Redirects
are not followed. Other 3xx and 4xx responses fail permanently and can be
retried manually from the dashboard.
The receiver must answer within 10 seconds. Return success only after your application has durably recorded the event.
Last updated Aug 22, 2026