Novaryq Developer Platform

Scopes

ScopeAccessDescription
orders.readreadRead orders and their status.
orders.writewriteCreate orders.
menu.readreadRead menu, items, and modifiers.
menu.writewriteSet item availability (86 or un-86).
inventory.readreadRead stock levels and counts.
inventory.writewriteReserved: no public API route requires this scope yet.
customers.readreadRead customer profiles (consent-gated).
webhooks.managewriteReserved: webhook subscriptions are managed in the developer console, not with an API key.

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.