Webhooks Overview
VaultsPay delivers real-time events to your HTTPS endpoint whenever something interesting happens — a user’s KYC result, a new card transaction, a balance change, and more.
Event delivery contract
- Method:
POST - Content-Type:
application/json - Signed: Every request carries an HMAC-SHA256 signature in the
VaultsPay-Signatureheader. - Idempotent: Every event has a unique
id. If you see the sameidtwice, you can safely ignore the duplicate. - Ordered: Events for a given resource are delivered in order, but no ordering guarantees across different resources.
The Event object
{
"id": "evt_01HX7ABCDEFG...",
"object": "event",
"type": "user.kyc.status_changed",
"created_at": "2026-04-24T14:52:03Z",
"api_version": "2026-04-01",
"livemode": false,
"data": {
"object": {
"id": "usr_01HX7...",
"object": "user",
"kyc": { "status": "approved", "level": "full" },
...
},
"previous_attributes": {
"kyc": { "status": "in_review" }
}
}
}Example handler (Node.js + Express)
webhook.js
import express from 'express'
import crypto from 'crypto'
const app = express()
const SECRET = process.env.VAULTSPAY_WEBHOOK_SECRET
app.post('/webhooks/vaultspay', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.header('VaultsPay-Signature')
const expected = crypto.createHmac('sha256', SECRET).update(req.body).digest('hex')
if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(400).send('Bad signature')
}
const event = JSON.parse(req.body.toString())
switch (event.type) {
case 'user.kyc.status_changed':
// ...
break
case 'card.transaction.posted':
// ...
break
}
res.status(200).send('ok')
})
app.listen(3000)