Skip to main content

Build a point-of-sale application

Use this roadmap when your point-of-sale (POS) or kitchen system receives orders from Otter and owns the menu catalog. A certification-ready POS flow ingests each order once, tracks status changes, and publishes the POS menu into Otter through Menus Manager.

Confirm the final requirements for your product with your Otter representative before you submit for certification.

Before you begin

  • Complete the shared readiness baseline.
  • Configure signed order webhooks.
  • Assign stable POS ids to menus, categories, items, modifier groups, and modifiers.
  • Define how Otter order and menu states map to your POS states.

How it fits

The Orders: receive into your system guide shows the inbound order flow. Its existing order diagram remains the source for that flow.

Publish a POS-owned menu into Otter and connected targets

Implementation roadmap

1. Receive orders from Otter

Handle Orders creation (orders.new_order), validate the signature before parsing the payload, and create the order once in the POS. Follow Handle create events for acknowledgement and processing behavior.

Handle Order status update (orders.order_status_update) and apply transitions to the same POS order. Preserve unknown or out-of-order transitions for investigation instead of silently replacing the current state.

2. Publish the POS-owned menu

Use Menus Manager because the POS is the source of truth:

  1. Create or update the catalog with POST /v1/menus.
  2. Poll GET /v1/menus/jobs/{jobId} until the job reaches SUCCESS or FAILED.
  3. Follow Publish menus to a target and verify the target job succeeds.
  4. Use Suspend or unsuspend entities with the same stable entity ids, then republish so targets receive the change.

Do not use the Otter-to-target Menus flow as the POS catalog source in this scenario.

Readiness checklist

  • New-order webhooks create one POS order when delivered once, more than once, or after a retry.
  • Status events update the existing order and preserve a trace of every transition.
  • Unsupported payloads fail visibly and retain enough context for troubleshooting.
  • A POS menu upsert reaches a terminal asynchronous job state.
  • Published menus match POS categories, items, modifier groups, prices, and availability.
  • Suspending and unsuspending an entity uses stable ids and propagates after republishing.
  • Webhook signatures, duplicate delivery, rate limits, and retryable API failures are handled.

Test before certification

  1. Receive a test order, acknowledge it promptly, and confirm the complete order appears in the POS.
  2. Replay the new-order event and verify that the POS does not create a duplicate order.
  3. Process status events, including a terminal state, and verify the correct POS order changes.
  4. Upsert a representative menu and poll until the job reaches SUCCESS.
  5. Publish the menu to one target, suspend an item, republish, then unsuspend and republish it.
  6. Submit an invalid menu payload and retain the failed job details for troubleshooting.

Evidence to collect

  • Webhook ids and POS order ids for original, replayed, and terminal-state events.
  • Logs showing signature validation, prompt acknowledgement, and asynchronous processing.
  • Menu upsert and publish job ids with final SUCCESS or expected FAILED results.
  • Before-and-after evidence for one suspended and unsuspended menu entity.
  • The shared evidence listed in Scenarios.

Common failures

SymptomLikely causeFix
Duplicate POS order appearsWebhook id or external order id is not used for deduplicationStore a stable deduplication key before processing the order
Event acknowledgement times outPOS work runs inside the webhook requestValidate, persist, acknowledge, then process asynchronously
Menu job reaches FAILEDInvalid shape or inconsistent entity idsInspect the job error and compare the payload with the API reference
Publish target is missingThe store is not linked to the target serviceVerify store pairing before publishing
Availability change does not propagateEntity ids changed or the menu was not republishedReuse upsert ids and publish after suspend or unsuspend

Next