Webhooks Setup & Events

Webhooks Setup & Events


Webhooks notify your application in real time when document events occur.


Setting up a webhook


  1. Go to Dashboard → Settings → Webhooks
  2. Click Add endpoint
  3. Enter your HTTPS endpoint URL
  4. Select which events to subscribe to (or select "All events")
  5. Copy the signing secret — you'll use it to verify payloads


Available events


Event

Fired when

document.created

A new document is created

document.status_changed

Any status transition

document.viewed

A signer or payer opens their link

document.signed

A signer completes signing

document.paid

Payment is confirmed

document.completed

Document reaches complete status


Webhook payload


{
"event": "document.signed",
"timestamp": "2026-04-15T15:00:00Z",
"data": {
"id": "doc_abc123",
"type": "signable",
"status": "all_signed",
"title": "NDA — Acme Corp",
"docUrl": "https://zipzign.com/sign/doc_abc123",
"pdfUrl": "https://zipzign.com/pdf/doc_abc123",
"amount": null,
"currency": null,
"payerEmail": null,
"payerName": null,
"signers": [
{
"id": "sgn_1",
"name": "Alice",
"email": "alice@example.com",
"status": "signed",
"signedAt": "2026-04-15T15:00:00Z"
}
],
"metadata": { "clientId": "client_789" },
"sandbox": false,
"createdAt": "2026-04-15T12:00:00Z",
"updatedAt": "2026-04-15T15:00:00Z"
}
}


Verifying webhook signatures


Each webhook request includes an X-ZipZign-Signature header. Verify it to ensure the payload is genuine:


const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}

// Express example
app.post('/webhooks/zipzign', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-zipzign-signature'];
const isValid = verifyWebhook(req.body, sig, process.env.ZIPZIGN_WEBHOOK_SECRET);

if (!isValid) {
return res.status(401).send('Invalid signature');
}

const event = JSON.parse(req.body);

if (event.event === 'document.completed') {
// Handle completion
}

res.status(200).send('OK');
});


Retry behavior


  • ZipZign retries failed webhook deliveries (non-2xx response) up to 5 times with exponential backoff
  • Retries occur at: 30s, 2m, 10m, 1h, 4h after initial failure
  • After 5 failed attempts, the delivery is marked failed


Best practices


  • Respond with 200 immediately, then process asynchronously
  • Use the id field to deduplicate events (retries send the same payload)
  • Always verify the HMAC signature before processing

Updated on: 16/04/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!