โ— API Beta Sandbox endpoints active. Production launching Q2 2026 โ€” reserve your developer slot for early access. Join the Waitlist โ†’

Build on Omnitopia

The unified API for restaurant operations. Inject orders into any kitchen, control SKUs across every platform, receive real-time webhook events. One integration, six platforms, zero per-transaction fees.

Connected Platforms
6
Avg Response Time
< 180 ms
Target Uptime
99.95 %
Rate Limit (Growth)
5K / min

01Quick Start

You're sending orders into a kitchen in 5 minutes. Here's the entire flow.

Step 1 โ€” Get an API key

Generate a sandbox API key from your developer dashboard. Sandbox keys work against the test environment and never bill real merchants. Production keys come after waitlist approval.

Step 2 โ€” Send your first order

One curl command, one order on a real (sandbox) kitchen ticket printer:

# Inject an order into the test kitchen at sandbox merchant M-TEST-001 curl -X POST https://api.omnitopia.ai/v1/order/inject \ -H "Authorization: Bearer sk_sandbox_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "merchantId": "M-TEST-001", "orderId": "DEMO-001", "source": "MyApp", "items": [ { "umsId": "BURGER_01", "qty": 1, "note": "No onions" } ], "total": 14.50 }'

Step 3 โ€” Receive the webhook

Within 200ms, Omnitopia sends a webhook to your configured endpoint confirming the order was accepted, queued, and printed. You're done.

02Authentication

All API requests require a Bearer token in the Authorization header. Tokens come in two flavors:

  • Sandbox keys โ€” prefixed sk_sandbox_. Free, unlimited, never bill anyone. Use for development and testing.
  • Production keys โ€” prefixed sk_live_. Available after waitlist approval. Tied to your billing account.

Key rotation

Rotate keys at any time from the developer dashboard. Old keys remain valid for 24 hours after rotation so you can deploy the new key without downtime. Compromised keys can be revoked instantly with a single API call.

Scopes

Tokens carry scopes that limit what they can do. Sandbox keys default to all scopes; production keys default to read-only and require explicit scope grants for write operations.

ScopeAllows
orders:readRead order history and status
orders:writeInject new orders, void or refund existing orders
menu:readRead SKU catalog and channel mapping
menu:writeSilence/restore SKUs across channels
webhooks:manageConfigure webhook endpoints and event subscriptions
printers:controlSend print jobs to CloudPRNT-enabled hardware

03Core Concepts

Universal Menu Schema (UMS)

Every menu item across every connected platform maps to a single UMS ID. A burger that's ITEM-892 in Toast, sq_burger_v3 in Square, and doordash_burger_2024 on DoorDash all resolve to BURGER_01 in Omnitopia. You write code against the UMS ID, Omnitopia handles the platform translation.

Order Injection vs POS Sync

There are two fundamentally different patterns for working with restaurant systems:

  • Order Injection (this API) โ€” your app sends an order TO the kitchen. The order didn't originate from a customer-facing app like DoorDash; it came from your kiosk, your AI agent, your custom mobile app. Omnitopia routes it through the POS as if it were a normal order, prints kitchen tickets, fires the KDS.
  • POS Sync (separate API) โ€” Omnitopia listens to the merchant's POS for orders that came in through normal channels (DoorDash, dine-in, etc.) and pushes those events out to your app via webhook. This is read-only โ€” your app observes, doesn't inject.

Merchant ID

Every order, webhook, and SKU operation is scoped to a single merchant. The merchantId field is required on every request. Sandbox merchants are prefixed M-TEST-; production merchants are prefixed M-PROD-.

04Order Injection

POSThttps://api.omnitopia.ai/v1/order/inject

Request payload

FieldTypeRequiredDescription
merchantIdstringREQUIREDThe merchant receiving the order
orderIdstringREQUIREDYour unique order ID โ€” used for idempotency. Resending the same orderId returns the original result.
sourcestringREQUIREDFree-text identifier for the originating app (e.g., "MyKiosk", "VoiceAgent v2.1")
itemsarrayREQUIREDArray of line items (see below)
totaldecimalREQUIREDOrder total in USD. Used for verification โ€” must match sum of items.
customerobjectoptionalCustomer name, phone, email for fulfillment notifications
tipdecimaloptionalTip amount in USD
printbooleanoptionalIf true, fires a kitchen ticket via CloudPRNT immediately. Defaults to true.
fireAtISO 8601optionalSchedule the order to fire at a future time (e.g., "2026-04-08T18:30:00Z")

Line item structure

FieldTypeRequiredDescription
umsIdstringREQUIREDUniversal Menu Schema item identifier
qtyintegerREQUIREDQuantity (1 or more)
pricedecimalREQUIREDUnit price in USD
notestringoptionalSpecial instructions ("No onions", "Extra spicy")
modifiersarrayoptionalArray of modifier UMS IDs (extra cheese, side substitution, etc.)

Successful response

{ "status": "accepted", "omnitopiaOrderId": "OT-ORD-9X7K2P", "posOrderId": "toast_4892", "queuedAt": "2026-04-07T14:32:18Z", "estimatedReadyAt": "2026-04-07T14:48:18Z", "printJobId": "prn_4d7e8f" }

Voids and refunds

Send a POST to /v1/order/{omnitopiaOrderId}/void to void an unfulfilled order, or /v1/order/{omnitopiaOrderId}/refund with a refund amount to refund a completed order. Both operations require orders:write scope.

05SDK Samples

Same order injection in five languages. Pick your stack.

curl -X POST https://api.omnitopia.ai/v1/order/inject \ -H "Authorization: Bearer $OMNITOPIA_KEY" \ -H "Content-Type: application/json" \ -d @'order.json'
const response = await fetch('https://api.omnitopia.ai/v1/order/inject', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.OMNITOPIA_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ merchantId: 'M-TEST-001', orderId: 'ORD-9982', source: 'MyKioskApp', items: [{ umsId: 'BURGER_01', qty: 1, price: 14.50 }], total: 14.50 }) }); const result = await response.json(); console.log(result.omnitopiaOrderId);
import requests, os response = requests.post( 'https://api.omnitopia.ai/v1/order/inject', headers={ 'Authorization': f'Bearer {os.environ["OMNITOPIA_KEY"]}', 'Content-Type': 'application/json' }, json={ 'merchantId': 'M-TEST-001', 'orderId': 'ORD-9982', 'source': 'MyPythonApp', 'items': [{'umsId': 'BURGER_01', 'qty': 1, 'price': 14.50}], 'total': 14.50 } ) print(response.json()['omnitopiaOrderId'])
using System.Net.Http.Json; var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new("Bearer", omnitopiaKey); var payload = new { merchantId = "M-TEST-001", orderId = "ORD-9982", source = "MyDotNetApp", items = new[] { new { umsId = "BURGER_01", qty = 1, price = 14.50m } }, total = 14.50m }; var result = await client.PostAsJsonAsync( "https://api.omnitopia.ai/v1/order/inject", payload);
$response = file_get_contents('https://api.omnitopia.ai/v1/order/inject', false, stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => "Authorization: Bearer {$_ENV['OMNITOPIA_KEY']}\r\n" . "Content-Type: application/json\r\n", 'content' => json_encode([ 'merchantId' => 'M-TEST-001', 'orderId' => 'ORD-9982', 'items' => [['umsId' => 'BURGER_01', 'qty' => 1]], 'total' => 14.50 ]) ] ]));

06Webhooks

Subscribe to events and receive HTTP POST notifications at your endpoint as soon as something happens. All webhooks are signed with HMAC-SHA256 โ€” verify the signature in the X-Omnitopia-Signature header before trusting payloads.

Event types

EventFires when
order.acceptedOrder successfully queued in the kitchen
order.printedKitchen ticket printed via CloudPRNT
order.readyKitchen marked the order ready for pickup/delivery
order.completedOrder picked up or delivered
order.voidedOrder voided before fulfillment
order.refundedRefund processed
sku.silencedSKU silenced across one or more channels
sku.restoredSKU restored to live status
sku.low_stockAuto-heal triggered low-stock detection

Retry policy

Failed webhook deliveries (any non-2xx response) are retried with exponential backoff: 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours. After 5 failures the webhook is marked failed and listed in your dashboard.

Signature verification

Verify the X-Omnitopia-Signature header matches the HMAC-SHA256 of the raw request body using your webhook signing secret:

const crypto = require('crypto'); function verifySignature(rawBody, signature, secret) { const expected = crypto.createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); }

07Hardware (CloudPRNT)

CloudPRNT is the protocol Omnitopia uses to fire kitchen tickets directly to thermal printers without going through the POS print queue. This bypasses the typical 30-90 second POS delay, putting paper in the cook's hands within ~2 seconds of order injection.

Compatible printers

  • Star Micronics โ€” TSP100, TSP650, mC-Print2, mC-Print3
  • Epson โ€” TM-T88VI, TM-m30II, TM-m50
  • Citizen โ€” CT-S310II, CT-E351 (with CloudPRNT firmware)

Setup

Plug the printer into the merchant's network. From the Omnitopia dashboard, add the printer by IP address and assign it to a merchant. Print queue routing happens automatically based on order type (kitchen tickets vs receipts vs labels).

Direct print API

If you need to fire a non-order print job (custom kitchen note, label, etc.), use the print endpoint:

POSThttps://api.omnitopia.ai/v1/print/job

08Rate Limits & Overage

Every paid tier includes a generous monthly call allowance and a steady-state per-minute throttle. If you exceed your included monthly calls, your orders keep flowing โ€” Omnitopia automatically meters overage at the rate shown below and adds it to your next invoice. No 429 errors. No interrupted service. No emergency upgrades on a busy weekend.

The per-minute steady rate is a separate throttle to protect platform stability against runaway loops. Bursts above the steady rate are absorbed by the burst capacity. Sustained spikes that exceed both steady and burst return HTTP 429 with a Retry-After header โ€” implement exponential backoff and you'll never hit it.

Tier Included Calls / Month Overage Rate Steady Rate Burst
Sandbox Unlimited (test only) โ€” 500 / min 1,000 / min
Starter 100,000 $0.05 / call 1,000 / min 2,000 / min
Growth 1,000,000 $0.03 / call 5,000 / min 10,000 / min
Enterprise Unlimited โ€” Custom Custom

How to think about overage

Overage is designed to be a safety net, not a revenue trap. The math: if you're consistently using 20%+ over your tier's included calls, upgrading to the next tier almost always costs less than the overage. Your dashboard surfaces this calculation in real time so you'll see "you'd save $X by upgrading to Growth" before you accumulate a bill that surprises you. Most merchants never see overage charges โ€” it exists so the few who do never face an outage.

09Error Codes

All errors return JSON with a code, message, and HTTP status.

CodeHTTPMeaning & how to handle
auth.missing_token401No Authorization header โ€” add Bearer token
auth.invalid_token401Token unrecognized or revoked โ€” rotate keys
auth.insufficient_scope403Token lacks required scope โ€” request elevated scope from dashboard
merchant.not_found404Merchant ID doesn't exist โ€” verify the ID
merchant.not_authorized403Your token isn't allowed to act on this merchant
ums.unknown_item422UMS ID not in this merchant's catalog โ€” check menu sync
order.duplicate_id409OrderId already used โ€” use idempotent retry or generate new ID
order.total_mismatch422Sum of items doesn't equal stated total
printer.offline503CloudPRNT printer not reachable โ€” order queued, will print on reconnect
rate_limit.exceeded429Slow down. Check Retry-After header.
internal.error500Something broke on our end โ€” safe to retry with same orderId

10Sandbox & Testing

The sandbox is a complete copy of the production API with test merchants, test SKUs, and test printers. Nothing in sandbox affects real merchants or real money.

Test merchants

  • M-TEST-001 โ€” Single-location burger joint, Toast + DoorDash + UberEats
  • M-TEST-002 โ€” Full-service restaurant, all 6 platforms connected
  • M-TEST-003 โ€” Multi-location franchisee, 12 connected printers

Simulating webhook events

Use the sandbox dashboard's "Trigger event" button to fire any event type at your webhook endpoint with realistic test data. Useful for end-to-end testing without placing actual orders.

Testing edge cases

Special test merchant IDs trigger specific failure modes for resilience testing:

  • M-TEST-SLOW โ€” All requests delayed 5 seconds (test your timeout handling)
  • M-TEST-FLAKY โ€” 30% of requests fail with 500 (test your retry logic)
  • M-TEST-PRINTER-OFFLINE โ€” All print jobs return 503 (test your error handling)

11Pricing Tiers

Flat monthly subscription. No per-transaction fees. No commission. No hidden cuts.

Starter
$199 / mo
  • 1 location
  • Up to 3 connected platforms
  • 100,000 API calls / month included
  • Overage: $0.05 / call (no service interruption)
  • 1,000 calls / min steady throttle
  • 5,000 webhook events / hour
  • Email support
Enterprise
Custom
  • Unlimited locations
  • All platforms + custom POS connectors
  • Unlimited API calls โ€” no overage, no throttle
  • Dedicated webhook capacity
  • White-glove onboarding
  • Dedicated success manager
  • SLA + uptime guarantees
What you'll never pay Omnitopia:

Per-transaction fees ยท per-order commissions ยท platform routing markups ยท hidden cuts on order volume. Your DoorDash bill is your DoorDash bill. Your Toast subscription is your Toast subscription. Omnitopia is a flat monthly subscription plus metered overage if you exceed your tier โ€” that's it. Most merchants never see overage charges.