Agent skill
OneSpan Webhooks Skill
Receive and authenticate OneSpan Sign (e-signature) callback notifications. Use when setting up a OneSpan callback endpoint, checking the callback key sent as Authorization: Basic, debugging 401s, or handling events such as PACKAGE_COMPLETE, DOCUMENT_SIGNED, SIGNER_COMPLETE and PACKAGE_DECLINE.
Install this skill
npx skills add hookdeck/webhook-skills --skill onespan-webhooks
OneSpan Sign sends JSON callback notifications (webhooks) to a URL you register whenever something happens to a package (a "transaction" in the new experience): created, sent, signed, completed, declined and so on. Payloads are not signed. The only authentication is the callback key you register, sent back in the Authorization header.
When to Use This Skill
- How do I receive OneSpan Sign callback notifications?
- How do I verify the OneSpan callback key in the
Authorization: Basicheader? - Does OneSpan sign webhook payloads? (No: shared callback key only)
- Why does my OneSpan callback endpoint return 401?
- How do I handle
PACKAGE_COMPLETE,DOCUMENT_SIGNEDorSIGNER_COMPLETEevents?
Verification (core)
The callback key is passed as Authorization: Basic {callbackKey}. That is the raw key, NOT base64(user:pass), so don't decode it as HTTP Basic. Store the whole header value (including the Basic prefix) as ONESPAN_AUTHORIZATION and compare the whole Authorization header to it:
const crypto = require('crypto');
// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
const ha = crypto.createHash('sha256').update(String(a)).digest();
const hb = crypto.createHash('sha256').update(String(b)).digest();
return crypto.timingSafeEqual(ha, hb);
}
function verifyOneSpanRequest(headers, expected = process.env.ONESPAN_AUTHORIZATION) {
if (!expected) return false; // never accept when unconfigured
const received = headers['authorization']; // full value, e.g. "Basic myCallbackKey"
return Boolean(received) && safeEqual(received, expected);
}
Return 401 when this fails (missing header or mismatch), 400 for a body that isn't a JSON object, and 2xx once handled. Read the body raw (express.raw({ type: '*/*' })) so any content type works, and parse JSON only after the credential check. Python and Next.js equivalents are in references/verification.md.
What this does and doesn't give you: a static shared credential authenticates the sender, not the body, and gives no replay protection (there is no signature and no timestamp). Use HTTPS, treat the callback key like a password, and rotate it if it leaks (register a new key with POST /api/callback or in the UI).
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Types
The event type is the name field in the JSON body. Documented events:
| Event | Meaning |
|---|---|
PACKAGE_CREATE | Package created |
PACKAGE_ACTIVATE | Package moved from DRAFT or DELETED to SENT |
DOCUMENT_SIGNED | A document was signed, or consent/disclosure accepted (documentId set) |
SIGNER_COMPLETE | A signer finished all documents |
PACKAGE_COMPLETE | Package completed signing (sessionUser is the last signer) |
PACKAGE_DECLINE | A recipient declined; message holds the reason |
EMAIL_BOUNCE | Email bounced; message holds the bounce type |
Others: COBROWSE_REQUEST, DOCUMENT_VIEWED, KBA_FAILURE, PACKAGE_ARCHIVE, PACKAGE_ATTACHMENT, PACKAGE_DEACTIVATE, PACKAGE_DELETE, PACKAGE_DISPUTE, PACKAGE_EXPIRE, PACKAGE_, PACKAGE_RESTORE, PACKAGE_TRASH, RECORDINGS_READY, ROLE_REASSIGN, SIGNER_LOCKED, TEMPLATE_CREATE and the eOriginal events EDEPOSIT_SUCCESS, EDEPOSIT_FAILURE, EDEPOSIT_FAILURE_ATTEMPT. See references/overview.md.
Body fields: name, sessionUser, packageId, documentId, message, createdDate (the docs show ISO strings and, for eDeposit events, epoch milliseconds).
Environment Variables
ONESPAN_AUTHORIZATION=Basic myCallbackKey # full header value: "Basic " + your callback key
Local Development
npx hookdeck-cli listen 3000 onespan --path /webhooks/onespan
No account required. Use the printed URL as the callback URL in OneSpan Sign.
Resources
- references/overview.md - Callback payloads and the full event list
- references/setup.md - Registering the callback URL and key (UI and
POST /api/callback) - references/verification.md - Header check in Node, Python and Next.js, gotchas
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests