Webhooks
Get notified in real-time when exchange rates change.
Overview
Webhooks deliver HTTP POST requests to your endpoint whenever rates change beyond a configured threshold. Use them to update prices in real-time, trigger repricing logic, or keep your database in sync — without polling.
Setting Up a Webhook
Register your endpoint
Go to Dashboard › Webhooks › Add Endpoint and fill in the fields below.
| Field | Details |
|---|---|
| Endpoint URL | Must be HTTPS. No localhost in production. |
| Currencies | Select which pairs to monitor (e.g. USD/JPY, EUR/GBP). |
| Threshold % | Trigger when rate changes by this %. Minimum: 0.1%. |
Verify your endpoint
When registered, xchangr8 sends a one-time verification POST. Your endpoint must respond with HTTP 200 and echo back the challenge.
Incoming verification payload
{
"type": "webhook.verify",
"challenge": "abc123xyz"
}
Your endpoint must respond with
{ "challenge": "abc123xyz" }
Handle events
Once verified, your endpoint will receive rate.changed events whenever a monitored pair crosses your threshold.
Webhook Payload Shape
{
"id": "evt_01HZXXXX",
"type": "rate.changed",
"timestamp": 1749340800,
"data": {
"pair": "USD/JPY",
"rate_before": 149.12,
"rate_after": 150.88,
"change_pct": 1.18,
"threshold_pct": 0.5
}
}
Event Types
| Event | Trigger |
|---|---|
| rate.changed | Rate moved beyond your configured threshold |
| rate.spike | Rate moved >2% in 1 hour (always sent, regardless of threshold) |
| webhook.verify | Endpoint verification challenge |
| webhook.test | Manual test triggered from dashboard |
Security — Verifying Signatures
Every webhook request includes an X-XC8-Signature header. Always verify it before processing the payload to prevent spoofed requests.
const crypto = require('crypto') function verifyWebhook(body, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(body) .digest('hex') return `sha256=${expected}` === signature } app.post('/webhooks/xc8', (req, res) => { const sig = req.headers['x-xc8-signature'] if (!verifyWebhook(req.rawBody, sig, process.env.XC8_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature') } // Process event res.status(200).send('OK') })
Retry Policy
Failed deliveries (non-2xx response or timeout) are retried automatically with exponential backoff.
- Attempt 1 Immediate
- Attempt 2 1 minute
- Attempt 3 5 minutes
- Attempt 4 30 minutes
- Attempt 5 2 hours
Best Practices
- ✓ Always verify signatures — reject requests that fail the HMAC check before doing any processing.
- ✓ Return 200 quickly — acknowledge the event immediately and process it asynchronously (queue, worker, etc.).
- ✓ Make handlers idempotent — the same event may be delivered more than once due to retries.
-
✓
Deduplicate on
id— store processed event IDs to safely ignore duplicates.