Signature format updated (2026-04)X-Simiz-Signature now uses t=<unix_timestamp>,v1=<hmac_sha256_hex> over signed payload ${timestamp}.${body} with 5 min replay tolerance. For production-ready snippets, see the Node.js SDK, Python SDK, or PHP SDK guides. Legacy sha256=<hex> snippets below are historical only.

Webhooks — REST API

Receiving webhooks

Simiz sends POST requests to your configured webhook URL with the event payload in the body and a signature in the X-Simiz-Signature header (format: t=<ts>,v1=<hex>).

Signature verification with cURL + openssl

# 1. Parse X-Simiz-Signature header: t=<timestamp>,v1=<hex>
TIMESTAMP=1713698400
V1="a3f2..."  # from header

# 2. Compute expected over signed_payload = "${TIMESTAMP}.${BODY}"
SIGNED_PAYLOAD="${TIMESTAMP}.<raw_request_body>"
EXPECTED=$(echo -n "$SIGNED_PAYLOAD" | openssl dgst -sha256 -hmac '<webhook_secret>' -r | awk '{print $1}')

# 3. Timing-safe compare EXPECTED vs V1 AND verify |now - TIMESTAMP| <= 300 seconds

Verification in different languages

const crypto = require('crypto');

const expected = crypto
  .createHmac('sha256', webhookSecret)
  .update(rawBody)
  .digest('hex');

const isValid = `sha256=${expected}` === signatureHeader;

Responding to webhooks

Your endpoint must:
  1. Return a 2xx status code within 30 seconds
  2. Process the event asynchronously if your logic takes longer
// Your response
HTTP/1.1 200 OK
Content-Type: application/json

{"received": true}

Testing with cURL

Send a simulated webhook to your local endpoint:
# Generate a test signature
SECRET="whsec_xxxxxxxxxxxx"
PAYLOAD='{"id":"evt_test","type":"payment.succeeded","data":{"id":"tx_test","amount":5000}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

# Send the webhook
curl -X POST http://localhost:3000/webhooks/simiz \
  -H "Content-Type: application/json" \
  -H "X-Simiz-Signature: sha256=$SIGNATURE" \
  -d "$PAYLOAD"