Skip to content

POST/v1/webhooks

Webhooks

Subscribe a URL to events such as sale.created, customer.created, online order updates and stock.low. Every delivery is signed with HMAC-SHA256 so you can verify it came from Nafaa, and a sample endpoint returns real example payloads for tools like Zapier.

Updated

Subscribe with POST /v1/webhooks and a body of { "url": "https://example.com/hooks/nafaa", "events": ["sale.created"] }. GET /v1/webhooks/events lists every event, GET /v1/webhooks/sample/{type} returns an example payload, and DELETE /v1/webhooks/{id} unsubscribes.

Events

sale.created, customer.created, online_order.created, online_order.accepted, online_order.dispatched, online_order.delivered, online_order.cancelled, online_order.returned and stock.low.

Verifying a delivery

Each request carries X-Nafaa-Event, X-Nafaa-Delivery (the event id; ignore repeats), X-Nafaa-Timestamp and X-Nafaa-Signature: t=<timestamp>,v1=<hex>. The signature is an HMAC-SHA256 of <timestamp>.<raw body> with your webhook secret.

Verify the signature

import crypto from 'node:crypto';

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split('=', 1) for p in header.split(','))
    signed = parts['t'].encode() + b'.' + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts['v1'])
Chat on WhatsAppEnglish ya Roman Urdu me