Use this as the canonical integration reference for any project that needs to accept crypto payments through Tempest Pay.
TEMPEST_SECRET_KEY.TEMPEST_WEBHOOK_SECRET.curl -X POST https://tempesttouchwallet.com/api/v1/charges -H 'Authorization: Bearer $TEMPEST_SECRET_KEY' -H 'Content-Type: application/json' -H 'Idempotency-Key: order-1042' -d '{
"amount": "25.00",
"currency": "USD",
"title": "Order #1042",
"reference": "1042"
}'
The response includes a hosted_url and a unique payment address. Redirect the customer there or show the pay address in your checkout flow.
Always verify the raw request body against the Tempest-Signature header before fulfilling the order.
import crypto from 'node:crypto';
app.post('/webhooks/tempest', express.raw({ type: '*/*' }), (req, res) => {
const sig = req.get('Tempest-Signature') || '';
const parts = sig.split(',').map((p) => p.split('=', 2));
const timestamp = Number(Object.fromEntries(parts).t);
const raw = req.body;
const expected = crypto.createHmac('sha256', process.env.TEMPEST_WEBHOOK_SECRET)
.update(String(timestamp) + '.')
.update(raw)
.digest('hex');
const valid = Number.isFinite(timestamp)
&& Math.abs(Date.now() / 1000 - timestamp) <= 300
&& parts.some(([k, v]) => k === 'v1' && crypto.timingSafeEqual(Buffer.from(v, 'hex'), Buffer.from(expected, 'hex')));
if (!valid) return res.sendStatus(400);
const event = JSON.parse(raw.toString('utf8'));
if (event.type === 'charge.paid') {
// fulfil event.data.object.reference
}
return res.sendStatus(200);
});
charge.createdcharge.processingcharge.partial_paymentcharge.paidcharge.underpaidcharge.expiredcharge.cancelledcharge.late_paymentUse event.id for idempotent fulfilment. The same event can arrive more than once.
Sandbox: /docs/sandbox.html · Examples: /docs/examples.html · Migration: /docs/migration.html · Spec: JSON · OpenAPI 3.1 · Postman