Use v3 menus as an integrator

End-to-end guide for reading, editing, publishing, exporting, and snoozing menus through the Flipdish Menu Management API.

Use v3 menus as an integrator

This guide walks you through working with menus through the Flipdish Menu Management API. It covers the lifecycle an integrator typically owns: discovering menus, reading the current version, editing, running publish checks, publishing a revision to sales channels, exporting for third-party channels, and snoozing items when something runs out.

🚧

Beta

The Menu Management API is currently in beta and may change without notice. We'll document any breaking change in release notes, but pin your integration to specific revisions and handle unknown fields defensively.

📘

Menu v3 (within the v3.0 API suite)

"v3" here refers to the menu version — menus have their own version number (v3 is current; v2 was the previous generation). That's distinct from the Flipdish API version: the Menu Management API documented in this guide is part of the Flipdish v3.0 API suite, alongside Sales Management, Org Management, and the rest. This guide covers the v3 menu lifecycle. If you're still integrating against v2 menus, the flow here doesn't apply.

⚠️

Known issues (as of publication)

Several endpoints currently have gaps that will affect integrations following this guide end-to-end. We're actively tracking fixes. In order of impact:

  • Publishing a newly-created menu may not take effect. POST /menuManagement/.../revisions/{revisionId}/publish can fail with "No storefronts are associated with this menu" even after a successful save. There is no public endpoint today that bridges a menu created through this API to a sales channel. Please contact us before building on end-to-end publish for new menus — see Report an issue or give feedback.
  • Pricing is not persisted on PUT /menus/{menuId}. The endpoint returns 200 and increments the revision, but pricingProfiles come back empty on the follow-up GET .../current. Structural edits (categories, items, names, allergens) do persist.
  • GET .../revisions/{revisionId}/publishCheck returns HTTP 500 with "Menu header not found". You can't programmatically validate a revision before publish today.
  • GET /menuManagement/orgs/{orgId}/menus/{menuId}/revisions returns HTTP 500. Use GET .../menus/{menuId}/current for the current draft (and fetch an individual revision by id with GET .../revisions/{revisionId} if you've persisted one) until this is fixed.

None of this blocks the read / save-draft path. If you hit any of the above, or see behaviour that contradicts this guide, please let us know via Report an issue or give feedback.

Prerequisites

Before you start, make sure you have:

  • A Flipdish OAuth2 client with access to the Menu Management API. See Getting Started for how to create one and request an access token.
  • Your orgId; every Menu Management path is scoped to an org: /menuManagement/orgs/{orgId}/....
  • A working understanding of the v3 menu shape. Read Menu Structure v3.0 first; this guide assumes you already know what a Category, Item, Modifier, ModifierMember, PricingProfile, CategoryGroup, and AvailabilityOverride are.

All examples use:

  • Base URL: https://api.flipdish.co
  • Auth header: Authorization: Bearer <your access token>

How the API is shaped

The Menu Management API is coarse-grained. There are no per-category or per-item endpoints; you work on the whole menu document (the shape described in Menu Structure v3.0). Every write is a full replacement of the menu body.

Operations fall into three groups:

GroupPurpose
Menu ManagementList, create, read, update, and archive menus.
Menu Management - RevisionsList revisions, read a specific revision, validate it, publish it to sales channels, or export it.
Menu Management - SnoozeTemporarily hide items without editing the menu itself.

Menus vs. revisions

In v3, a menu has a current (latest) version and a list of revisions. Every PUT /menus/{menuId} creates a new revision and bumps revisionId — there is no in-place draft that multiple saves write to. A revision becomes live only when it's published to one or more sales channels.

This means each save is its own immutable snapshot: you can iterate on a menu by PUTing it multiple times, then pick any resulting revisionId to validate and publish.

Complete endpoint reference

All paths are relative to https://api.flipdish.co and scoped by orgId.

Menus

MethodPathPurposeReference
GET/menuManagement/orgs/{orgId}/menus/headersList menu headers (lightweight index). Supports includeArchived.get menu headers
GET/menuManagement/orgs/{orgId}/menus/publishedList every menu that currently has a published revision.get published menus
POST/menuManagement/orgs/{orgId}/menusCreate a new menu (body: CreateMenuSchema).create menu
GET/menuManagement/orgs/{orgId}/menus/{menuId}/currentFetch the current (latest) version of a menu.get current menu
PUT/menuManagement/orgs/{orgId}/menus/{menuId}Replace the menu in place (body: UpdateMenuSchema).update menu
DELETE/menuManagement/orgs/{orgId}/menus/{menuId}Archive (soft-delete) the menu.archive menu

Revisions

MethodPathPurposeReference
GET/menuManagement/orgs/{orgId}/menus/{menuId}/revisionsList all revisions of the menu.list revisions
GET/menuManagement/orgs/{orgId}/menus/{menuId}/revisions/{revisionId}Fetch a specific revision.get revision
GET/menuManagement/orgs/{orgId}/menus/{menuId}/revisions/{revisionId}/publishCheckValidate whether the revision is publishable.publish check
POST/menuManagement/orgs/{orgId}/menus/{menuId}/revisions/{revisionId}/publishPublish the revision to the supplied selectedSalesChannelIds.publish revision
GET/menuManagement/orgs/{orgId}/menus/{menuId}/revisions/{revisionId}/export/{channel}Export the revision in a channel-specific format. Supports referencePriceDispatchType.export revision

Snooze

MethodPathPurposeReference
GET/menuManagement/orgs/{orgId}/menus/{menuId}/snoozesList the current snooze state for items. Filter by propertyIds.list snoozes
POST/menuManagement/orgs/{orgId}/menus/{menuId}/snoozesSnooze one or more items (body: array of PublicSnoozeItemSchema).snooze items
POST/menuManagement/orgs/{orgId}/menus/{menuId}/un-snoozesUn-snooze items (body: array of PublicUnSnoozeItemSchema).un-snooze items

End-to-end integrator flow

A typical integration follows these steps. The sections below show a runnable curl example for each.

  1. Authenticate and obtain an access token.
  2. Discover the menus that belong to the org.
  3. Fetch the current menu.
  4. Edit the menu and PUT it back; this creates a new revision.
  5. Validate the revision with a publish check.
  6. Publish the revision to the chosen sales channels.
  7. Optionally export the revision for external channels, or snooze items.

1. Authenticate

curl --request POST \
  --url https://api.flipdish.co/identity/connect/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials \
  --data client_id=<your_client_id> \
  --data client_secret=<your_client_secret> \
  --data scope=api

The response includes an access_token that you pass as Authorization: Bearer <token> on every subsequent call.

2. List menus

Start from the menu headers endpoint; it returns a lightweight index so you can pick the menu you want to work with without pulling the full document.

curl --request GET \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/headers?includeArchived=false' \
  --header 'Authorization: Bearer <access_token>'

If you only care about what's currently live for the customer, call the published-menus endpoint instead:

curl --request GET \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/published' \
  --header 'Authorization: Bearer <access_token>'

3. Fetch the current menu

Once you have a menuId, pull the current working version. This is the full menu document; see Menu Structure v3.0 for the shape.

curl --request GET \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/current' \
  --header 'Authorization: Bearer <access_token>'

Hold onto the returned revisionId; you'll need it when you publish.

4. Edit and save

The update endpoint replaces the entire menu. Fetch the current menu, mutate the fields you care about (add a category, reprice an item, add a modifier member, etc.), then PUT the full document back. Every PUT creates a new revision and bumps revisionId — each save is a fresh, immutable snapshot, not an in-place edit of an existing draft. Re-fetch GET .../current after each save to pick up the new revisionId.

curl --request PUT \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data @updated-menu.json
⚠️

Known issue — pricing is not persisted

On a PUT /menus/{menuId} the response is 200 and structural edits (categories, items, names, allergens) persist, but pricingProfiles on items are silently dropped — they come back empty on the follow-up GET .../current regardless of taxable or *TaxablePrice values you send. We're tracking this; use the admin UI to set pricing in the meantime, and let us know if it's blocking you.

Guidelines for edits

  • Preserve IDs you don't own. If an item already has an id, keep it; changing or omitting it can create a new entity instead of updating the existing one.
  • Keep the top-level menu id in the body. UpdateMenuSchema lists it as required; omitting it will fail validation.
  • Keep cross-references intact. ModifierMember.parentModifierId must point at a Modifier.id that exists in the same menu, and CategoryGroup.categoryIds must reference valid Category.ids.
  • Every item needs a PricingProfile for each price band your property uses, with prices filled in for every dispatch type (collectionPrice, deliveryPrice, dineInPrice, takeawayPrice). (See the known issue above about pricing persistence.)
  • AvailabilityOverride rules are the right place to express "weekday lunch only" or "Deliveroo-only" variants; do not duplicate items to model availability.

To create a fresh menu instead of updating, POST to /menuManagement/orgs/{orgId}/menus with a CreateMenuSchema body.

5. Run a publish check

Before publishing, validate the revision. The publish-check endpoint returns any structural or business-rule violations that would block a publish, so you can surface them to the user (or fail your CI job) without touching any customer-facing channel.

curl --request GET \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/revisions/<revisionId>/publishCheck' \
  --header 'Authorization: Bearer <access_token>'
⚠️

Known issue — endpoint currently returns HTTP 500

publishCheck is currently returning 500 with {"error":{"message":"Menu header not found","code":"unknown_error"}} on every call, including against revisions that are visible in GET .../menus/headers. Skip this step until fixed, or rely on the errors returned by the publish call itself. Please report any occurrences so we can prioritise the fix.

6. Publish the revision

Publishing is atomic across the sales channels you pass. You choose the revision, you choose the channels; nothing else goes live until you call this.

curl --request POST \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/revisions/<revisionId>/publish' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "selectedSalesChannelIds": ["sc123", "sc456"]
  }'

selectedSalesChannelIds must contain at least one ID. To roll back, publish an earlier revisionId to the same channel list.

⚠️

Known issue — new menus may not publish

Calls can currently fail with invalid_request: "No storefronts are associated with this menu. You cannot publish a menu without any storefronts" even when the menu was created and saved successfully through this API, and there is no public endpoint today that associates a new Menu-Management-API menu with a sales channel. Publishing updates to existing menus already associated with a sales channel works; publishing a brand-new menu end-to-end through the public API does not yet. (The error message still uses the legacy term "storefronts"; read it as "sales channels".) If your integration needs to stand up a new menu, contact us first — we'll confirm the supported path for your use case.

7. Export (optional)

If you need the revision in an external channel's format (for example, to ship to a marketplace), call the export endpoint with the channel identifier.

curl --request GET \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/revisions/<revisionId>/export/<channel>?referencePriceDispatchType=Delivery' \
  --header 'Authorization: Bearer <access_token>'

referencePriceDispatchType controls which of the four PricingProfile prices (Collection, Delivery, DineIn, TakeAway) is used as the reference price when the target format only supports a single price per item.

Working with revisions

Revisions are immutable once created, and a new one is produced on every PUT /menus/{menuId}. Use them to:

  • Audit what changed, when, and by whom; GET .../revisions/{revisionId} returns the full body of a specific revision.
  • Roll back by publishing a known-good earlier revision.
  • Coordinate multiple channels; you can publish the same revision to additional channels later without re-saving the menu.
⚠️

Known issue — listing all revisions currently returns HTTP 500

GET /menuManagement/orgs/{orgId}/menus/{menuId}/revisions is currently failing with a response-validation error on an archived field. In the meantime, read the latest revisionId from GET .../menus/{menuId}/current after each save, and store revision IDs yourself as you create them. GET .../revisions/{revisionId} (single revision) is unaffected.

Snoozing items

Snoozing temporarily removes items from the live menu without editing the menu body. This is the right tool for "we're out of fish today"; the edit is lightweight, doesn't require a publish, and is reversible in a single call.

List the current snooze state (optionally scoped to specific stores with propertyIds):

curl --request GET \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/snoozes?propertyIds=prop123&propertyIds=prop456' \
  --header 'Authorization: Bearer <access_token>'

Snooze items by POSTing an array of snooze entries:

curl --request POST \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/snoozes' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '[ { ... PublicSnoozeItemSchema ... } ]'

Reverse a snooze with the un-snooze endpoint:

curl --request POST \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>/un-snoozes' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '[ { ... PublicUnSnoozeItemSchema ... } ]'

Snooze vs. edit vs. availability override

ScenarioUse
An item is temporarily unavailable (today, a few hours).Snooze
An item is only available at certain times or on certain dispatch types.AvailabilityOverride on the item
An item should be removed from the menu permanently, or its price/description is changing.Edit + publish

Archiving a menu

DELETE on a menu performs a soft delete; the menu is archived, not wiped. Archived menus stop appearing in the default GET .../menus/headers response; set includeArchived=true to see them.

curl --request DELETE \
  --url 'https://api.flipdish.co/menuManagement/orgs/<orgId>/menus/<menuId>' \
  --header 'Authorization: Bearer <access_token>'

Error handling and best practices

  • Send a User-Agent, required on every request. See User Agents.
  • Handle errors consistently. The Flipdish API returns structured error responses; see Error Handling.
  • Be defensive on reads. Since the API is in beta, unknown fields can appear in responses. Ignore what you don't understand rather than failing.
  • Preserve round-trip fidelity. When you GET .../current, edit, and PUT back, pass through fields you didn't intend to change (including IDs and cross-references) instead of regenerating the document.
  • Always publish-check before publish (once the known issue with publishCheck is resolved). Errors caught in publishCheck are cheaper than errors caught by a customer.
  • Treat a revisionId as a pointer to a frozen document. Every PUT produces a new revisionId; after any PUT, re-fetch .../current to get the latest one before publishing or validating.

Report an issue or give feedback

This API is in beta and we're actively iterating. If you hit one of the known issues, see behaviour that contradicts this guide, or have feedback on the shape of the API, please get in touch:

To help us diagnose quickly, include:

  • Your orgId.
  • The menuId and revisionId involved.
  • The HTTP method and full path you called.
  • Your request body (redact any secrets).
  • The full response body and any x-request-id / correlation IDs from the response headers.
  • The approximate time (UTC) of the call.

That context lets us correlate your calls with server logs directly.

Related reading