Novaryq Developer Platform

Scopes

ScopeAccessDescription
orders.readreadRead orders and their status.
orders.writewriteCreate and update orders.
menu.readreadRead menu, items, and modifiers.
menu.writewriteManage menu, items, availability (86).
inventory.readreadRead stock levels and counts.
inventory.writewriteAdjust stock, submit counts.
customers.readreadRead customer profiles (consent-gated).
payments.readreadRead payment + settlement records.
webhooks.managewriteCreate and manage webhook subscriptions.

Tiers and rate limits

TierReq/minBurstDaily quotaWrite
Sandbox30605000no
Standard partner120240200000yes
Certified partner60012005000000yes
Internal / first-party600012000uncappedyes

Idempotency

Send an Idempotency-Key header on any mutation you might retry. A replay of the same request returns the original result instead of performing the work twice — which is what makes an offline queue or a flaky network safe.

A key is bound to the request that first used it. Reusing the same key with a CHANGED body is a conflict, not a silent success: the server refuses rather than letting one key settle two different payments.

curl -X POST https://novaryq.com/v1/orders/ORDER_ID/payments \
  -H "Authorization: Bearer $NQ_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"method":"CASH","amount":"24.99"}'

Webhooks and signature verification

Every webhook carries an HMAC-SHA256 of the RAW request body in the X-NQ-Signature header, hex encoded. Compute the same HMAC with your endpoint secret over the bytes you received — not over a re-serialised object, which will not match — and compare in constant time.

Verification is fail-closed in production: an unsigned or wrongly signed delivery is rejected, never processed on the assumption it is probably fine.

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody MUST be the exact bytes received, before any JSON parsing.
export function verify(rawBody, signatureHeader, secret) {
  const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
  const a = Buffer.from(signatureHeader.trim(), 'utf8');
  const b = Buffer.from(expected, 'utf8');
  return a.length === b.length && timingSafeEqual(a, b);
}

Errors

Errors are standard HTTP status codes with a JSON body carrying a human-readable message. Treat 4xx as final — a rejected request will be rejected identically on retry, so retrying it only hides the reason. Retry 5xx and network failures, with backoff.

One case deserves its own handling: a payment whose outcome is unknown returns 503 and is reconciled server-side. Do not re-tender it — that is how a guest gets charged twice.

Sandbox

Sandbox credentials are read-only by design: orders, menu and inventory reads, no writes. That is deliberate — an integration that cannot yet be trusted with a write should not be able to make one while it is being built.

Capability registry

Novaryq publishes a capability registry at /v1/capabilities with an explicit proof level for every integration — catalog, simulator, partner-approved, certified or observed in production. Build against what it says, not against what a feature list implies: a capability that is not certified is not a promise.