🚀 VaultsPay API v1 is live. See what's new →
WebhooksOverview

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-Signature header.
  • Idempotent: Every event has a unique id. If you see the same id twice, 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)

Read more