Nunua Pro Developers
Building

Webhooks

For a POS that runs in the cloud: we POST every order event to your HTTPS address as it happens, signed so you can prove it came from us.

Delivery

The shop owner sets the webhook address in the Business app and receives a webhook secret (whsec_…), shown once, to enter in your POS. Each event is a POST with this body:

Body
{ "event_id": 1042, "type": "order.confirmed", "created_at": "2026-11-03T10:15:22+03:00", "order": { ... } }

The order is the same object the event feed returns.

Headers

HeaderContains
X-Nunua-EventThe event type, for example order.confirmed.
X-Nunua-Event-IdA unique id. De-duplicate on it.
X-Nunua-TimestampUnix seconds when it was sent.
X-Nunua-Signaturesha256= followed by the hex HMAC-SHA256 of "{timestamp}.{raw body}", keyed with the shop's webhook secret.

Verifying the signature

Verify against the raw request body, before any JSON parsing, and reject timestamps older than a few minutes so a captured request can't be replayed.

const crypto = require('crypto');

// Verify a Nunua Pro webhook. `rawBody` must be the RAW request body (a Buffer or string),
// not JSON.parse'd and re-stringified. (Express: express.raw({ type: 'application/json' }).)
function verifyNunuaWebhook(rawBody, timestamp, signatureHeader, secret, tolerance = 300) {
  // Reject old requests so a captured one cannot be replayed later.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > tolerance) return false;
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(`${timestamp}.`).update(rawBody).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader || '');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

module.exports = { verifyNunuaWebhook };

// In your endpoint:
//   const ok = verifyNunuaWebhook(req.body, req.get('X-Nunua-Timestamp'), req.get('X-Nunua-Signature'), process.env.NUNUA_WEBHOOK_SECRET);
//   if (!ok) return res.sendStatus(401);
//   ...record the sale, then answer 2xx quickly.

Retries and timeouts

  • Answer with any 2xx within 10 seconds. If recording the sale is slow, accept the webhook and do the work in the background.
  • Anything else, or a timeout, is retried with growing delays for 24 hours. The event feed has every event regardless.
  • Addresses must be https on a public host. Private networks are refused, and redirects aren't followed.