publishMenu
Push the menu's current SAVED state to the delivery platforms (ONE-2780).
⚠️ SAVING A MENU NEVER CHANGES WHAT GUESTS SEE — THIS CALL DOES, and there is no unpublish. The published docs put that sentence in bold and it is repeated here for the same reason.
Asynchronous. The reply is an acknowledgement carrying a publicationId; per-store, per-platform outcomes arrive from fetchMenuPublications and on the menu.publication.completed webhook. A failed store carries the platform's error verbatim where the platform provides one — some platforms report only success/failure.
WHAT IS SENT. A publication always submits each storefront's COMPLETE menu set, because platforms replace rather than merge. menuId therefore selects WHICH storefronts are published to, not what they receive: publishing menu A to a storefront that also carries menu B re-submits BOTH. See menuId for how that surfaces on the read side.
Scope: menuId must resolve under this organization by the SAME predicate fetchMenu uses, and every storeId supplied must be a storefront this organization owns. Anything else is 404 with NOTHING published — never a partial write, and never a distinction between "does not exist" and "not yours".
Request
- menuIdstring
The menu to publish. Required — the published schema lists it under
required: [menuId], and this API returns404for a menu that does not exist AND for one belonging to another organization, indistinguishably.WHAT THIS SELECTS.
menuIdchooses WHICH STOREFRONTS are published to (the ones it is assigned to); it does not narrow WHAT is sent to them. Each selected storefront receives its COMPLETE active menu set, because delivery platforms replace rather than merge — see the operation's own doc comment. - storeIdsstring[]
Narrow the publication to specific storefronts. Omit to publish to EVERY store the menu is assigned to — the published description's own wording.
A
storeIdhere that this organization does not own, or that the menu is not assigned to, is404, and NOTHING is published: the request is rejected whole rather than silently applied to the subset that did resolve. A partial publish a partner did not ask for is worse than a rejected one, because there is no unpublish.
{
"menuId": "00000000-0000-0000-0000-000000000000",
"storeIds": [
"<storeIds>"
]
}Responses
- publicationIdstring
Poll this with
fetchMenuPublications({ publicationIds: [publicationId] }). - statusstring
Always
queuedon success — the published schema declaresenum: [queued], a single-valued enum, so this field carries no information beyond "accepted". It is echoed rather than dropped because the published schema names it.Deliberately NOT the internal job's own status. OneTablet's
PublishJobmay already have advanced past its PENDING state by the time this returns (its per-store tasks are enqueued inside the same call); reporting that internal state here would put a value outside the published enum on the wire.Possible values: [queued]
About Menus
Menus — two reads (ONE-2726) and one write (ONE-2780), the section's full published surface.
publishMenu is the ONLY WRITE here and the only operation on this whole API that reaches live DoorDash / UberEats / Grubhub storefronts. There is no unpublish. ONE-2724 once held it behind an undocumented header; ONE-2908 removed that, so today the only thing standing in front of it is authentication plus the org scope check below. It is still absent from MANAGEMENT_API_READ_METHODS in ManagementApiKeyHook, on purpose — that list is now the platform's read/write CLASSIFIER (ONE-2890, ONE-2718 build on it), and a write on a read list would be a lie. Do not "fix" that by adding it.
All three operations are org-scoped to the organization the api key resolves to. Cross-tenant and unknown ids are INDISTINGUISHABLE by design — every one of the three returns the published 404 shape for both cases, same convention as StoresApi / ItemAvailabilityApi. On publishMenu that rule has teeth beyond information disclosure: a foreign menuId must never become a write, so the scope check runs BEFORE anything is enqueued.
NOT IMPLEMENTED: replay via Idempotency-Key. The published contract declares the parameter on publishMenu, and nothing on the platform implements idempotent replay today — the same honest gap ItemAvailabilityApi's header records for setItemAvailability (ONE-2621 decision 3). ⚠️ IT MATTERS MORE HERE: a retried publishMenu creates a SECOND publication and re-submits to the platforms rather than returning the first result. That is not corrupting — a publication is a full replace of the same saved state, so the second is a no-op in content — but it doubles platform traffic and produces two publicationIds for one intent. Callers should treat a timeout as "may have succeeded" and check fetchMenuPublications before retrying.