Skip to main content

Signature Verification

Every webhook request includes a signature header that you should verify to ensure the request is genuinely from Ikawaari.

How It Works​

Each webhook endpoint has a unique signing secret (starts with whsec_). Ikawaari uses this secret to generate an HMAC-SHA256 signature included in the Ikawaari-Signature header.

The secret is shown only once at creation or after rotation. If you no longer have it, rotate the secret and update your merchant backend. This secret is different from your Ikawaari API key.

Verification must use the exact raw body received by your server. Do not parse and re-serialize JSON before computing the signature: whitespace, ordering, or encoding changes can make a valid request fail verification.

Verification Steps​

1. Extract the signature​

Ikawaari-Signature: t=1708300800,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

2. Prepare the signed payload​

{timestamp}.{raw_body}

3. Compute the expected signature​

import Ikawaari from '@ikawaari/sdk';

const client = new Ikawaari({ apiKey: process.env.IKAWAARI_API_KEY });

const event = client.webhooks.constructEvent(
rawBody,
request.headers['ikawaari-signature'],
process.env.IKAWAARI_WEBHOOK_SECRET
);

With Express, expose the raw body on this route:

app.post('/webhooks/ikawaari', express.raw({ type: 'application/json' }), (req, res) => {
const event = client.webhooks.constructEvent(
req.body.toString('utf8'),
req.headers['ikawaari-signature'],
process.env.IKAWAARI_WEBHOOK_SECRET
);

res.sendStatus(200);
});

Without the SDK:

const crypto = require('crypto');

function verifyWebhookSignature(payload, header, secret) {
const [tPart, vPart] = header.split(',');
const timestamp = tPart.split('=')[1];
const signature = vPart.split('=')[1];

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

// Timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}

4. Reject stale events​

Check that the timestamp is within 5 minutes of the current time to prevent replay attacks.

warning

Always verify webhook signatures in production. Never trust webhook payloads without verification.