Webhooks
Recevez les événements en temps réel et vérifiez les signatures HMAC.
Configuration
Passez webhook_url lors de la création d'une signature request, ou configurez une URL
globale au niveau de l'organisation dans le dashboard.
{
"webhook_url": "https://yourapp.com/webhooks/signlift",
"...": "..."
}Événements
| Event | Déclencheur |
|---|---|
signature_request.created | Création de la requête. |
signer.notified | Email/SMS d'invitation envoyé. |
signer.signed | Un signataire a signé (utile en mode séquentiel). |
signature_request.completed | Tous les signataires ont signé. |
signature_request.completion_notified | Emails de complétion envoyés au demandeur/signataires. |
signature_request.expired | La requête a dépassé validity_days. |
Format du payload
{
"event": "signature_request.completed",
"occurred_at": "2026-05-16T15:12:43Z",
"data": {
"signature_request_id": "sr_01HZQM...",
"signed_at": "2026-05-16T15:12:43Z",
"documents": [
{ "id": "doc_01HZQK...", "signed_pdf_url": "https://..." }
]
}
}Vérification HMAC
Chaque webhook contient un header X-Signlift-Signature au format
t=TIMESTAMP,v1=HMAC_HEX. Calculez le HMAC SHA-256 de ${TIMESTAMP}.${RAW_BODY} avec
votre webhook secret, et comparez en temps constant.
require 'openssl'
def verify_signlift_webhook(raw_body, header, secret)
parts = header.split(',').to_h { |p| p.split('=', 2) }
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, "#{parts['t']}.#{raw_body}")
Rack::Utils.secure_compare(expected, parts['v1'])
endimport crypto from 'node:crypto'
function verifySignliftWebhook(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}Retry policy
En cas d'échec (HTTP ≠ 2xx ou timeout 10s), Signlift retente avec backoff exponentiel : immédiat, 30s, 2min, 10min, 1h, puis abandon. Tous les essais sont visibles dans le dashboard.
Pour la robustesse, votre handler doit être idempotent (déduplication via event_id
inclus dans le payload).