Webhooks

Subscribe to real-time events from YionStack. When something happens (invoice paid, deal moved, order created), we send an HTTP POST to your registered endpoint.

Event catalogue

Delivery format

Each webhook delivery is an HTTP POST with JSON body and the following headers:

HeaderDescription
X-YionStack-SignatureHMAC-SHA256 signature of the request body
X-YionStack-TimestampUnix timestamp (seconds) when the event was sent
X-YionStack-EventEvent type (e.g. invoice.paid)
Content-Typeapplication/json

Signature verification

Always verify the X-YionStack-Signature header to ensure the webhook was sent by YionStack and not tampered with.

const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHash('sha256')
    .update(secret + '.' + body)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your Express handler:
app.post('/webhooks/yionstack', (req, res) => {
  const signature = req.headers['x-yionstack-signature'];
  const timestamp = req.headers['x-yionstack-timestamp'];
  const body = JSON.stringify(req.body);

  // Reject if timestamp is more than 5 minutes old (replay protection)
  const age = Math.floor(Date.now() / 1000) - Number(timestamp);
  if (age > 300) return res.status(400).send('Stale webhook');

  if (!verifyWebhook(body, signature, 'your_webhook_secret')) {
    return res.status(401).send('Invalid signature');
  }

  // Process the event
  const { event, data } = req.body;
  console.log('Received:', event, data);
  res.status(200).send('OK');
});

Retry policy

If your endpoint returns a non-2xx status code or times out (10 seconds), we retry with exponential backoff:

  • Attempt 1: immediate
  • Attempt 2: after ~2 seconds
  • Attempt 3: after ~4 seconds

After 3 failed attempts, the delivery is marked as failed. You can view delivery history in Settings → Developer.