For the complete documentation index, see llms.txt. This page is also available as Markdown.

Security

Signature Verification

Every webhook delivery is signed so you can verify it came from TokenBot. Each request includes these headers:

Header
Description

X-TokenBot-Signature

sha256=<hex_digest> HMAC of the payload

X-TokenBot-Timestamp

Unix seconds when the signature was created

X-TokenBot-Event

The event type (e.g. trade.executed)

X-TokenBot-Delivery-Id

Unique delivery ID (use for idempotency)

How It Works

  1. TokenBot builds the string ${timestamp}.${raw_body}.

  2. It computes HMAC-SHA256(secret, that_string) and sends it as X-TokenBot-Signature: sha256=<hex>, with the timestamp in X-TokenBot-Timestamp.

  3. You recompute the same HMAC and compare in constant time.

  4. Reject deliveries whose timestamp is older than your tolerance (TokenBot uses a 5-minute replay window).

Node.js Example

const crypto = require('crypto');

function verifyWebhook(rawBody, signature, timestamp, secret, toleranceSeconds = 300) {
  // Reject stale deliveries
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - Number(timestamp)) > toleranceSeconds) return false;

  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`, 'utf8')
    .digest('hex');

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

// Express middleware (note: raw body is required)
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const ok = verifyWebhook(
    req.body,
    req.headers['x-tokenbot-signature'],
    req.headers['x-tokenbot-timestamp'],
    process.env.WEBHOOK_SECRET
  );
  if (!ok) return res.status(401).send('Invalid signature');

  const event = JSON.parse(req.body);
  // Process event...
  res.status(200).send('OK');
});

Python Example

Secrets

Webhook signing secrets are prefixed whsec_ and are shown only once, when the webhook is created. Rotate a secret with POST /v1/webhooks/:id/rotate-secret (the previous secret keeps working for a short grace window).

Best Practices

  • Always verify signatures and the timestamp before processing events.

  • Use crypto.timingSafeEqual (Node.js) or hmac.compare_digest (Python) to prevent timing attacks.

  • Deduplicate using X-TokenBot-Delivery-Id (or the payload's event_id).

  • Respond with 2xx quickly; process events asynchronously.

Last updated

Was this helpful?