4 operations. Every schema and example on this page is generated from the platform contract.
Merchant read of the store’s menu items. Removed items (soft-deleted) are excluded; merchant-hidden items are included (flagged via is_available/checkout_enabled).
Store whose menu to list (also authorises the merchant).
imagevideocurl -G "https://www.membber.com/api/v1/menu-items" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
--data-urlencode "store_id=6659c139-0000-4000-8000-d0c500000066"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/menu-items", {
params: { query: { store_id: "6659c139-0000-4000-8000-d0c500000066" } },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.listMenuItems(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"items": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"description": "Added at the front desk",
"category": "<category>",
"emoji": "<emoji>",
"image_url": "https://example.com/image.jpg",
"product_media": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"type": "image",
"url": "https://example.com/image.jpg",
"thumbnail_url": "https://example.com/image.jpg",
"sort_order": 1
}
],
"contains_allergens": [
"<contains_allergen>"
],
"dietary_tags": [
"<dietary_tag>"
],
"ingredients": "<ingredients>",
"nutrition_summary": "<nutrition_summary>",
"is_popular": true,
"is_available": true,
"checkout_enabled": true,
"stock_tracking_enabled": true,
"stock_quantity": 1,
"stock_remaining": 1,
"sold_out": true,
"collect_eligible": true,
"available_now": true,
"collect_prep_minutes": 1,
"price_pence": 1500,
"currency": "GBP",
"sort_order": 1
}
]
}Merchant creates a menu item. The service validates name + price and normalises all fields. Broadcasts a menu_item_created realtime event so customer apps re-pull the menu. No HTTP idempotency key (identical to the legacy route), a create is not deduplicated.
Store the item belongs to (also authorises the merchant).
Item name (required; max 120 chars).
Price in pence (required; 0..10,000,000).
A menu_items row (write result, raw DB shape).
curl -X POST "https://www.membber.com/api/v1/menu-items" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"name": "Example name",
"price_pence": 1500
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/menu-items", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name",
price_pence: 1500
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.createMenuItem(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name",
pricePence: 1500
))
).ok.body.json
print(response){
"item": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"name": "Example name",
"price_pence": 1500,
"currency": "GBP",
"is_available": true,
"checkout_enabled": true
}
}Merchant removes a menu item. Soft delete (order-history integrity): flips visibility AND stamps deleted_at so the list can tell a REMOVED item apart from a merchant-HIDDEN one. Broadcasts a menu_item_archived realtime event. Idempotent. store_id is supplied as a query parameter.
Store the item belongs to (also authorises the merchant).
curl -X DELETE "https://www.membber.com/api/v1/menu-items/b9bf0b8e-0000-4000-8000-d0c5000000b9?store_id=6659c139-0000-4000-8000-d0c500000066" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.DELETE("/api/v1/menu-items/{itemId}", {
params: { path: { itemId: "b9bf0b8e-0000-4000-8000-d0c5000000b9" }, query: { store_id: "6659c139-0000-4000-8000-d0c500000066" } },
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.archiveMenuItem(
path: .init(itemId: "b9bf0b8e-0000-4000-8000-d0c5000000b9"),
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"archived": true
}Merchant updates a menu item. Stock edits preserve in-flight reservations (set_menu_item_stock); a plain edit cannot silently resurrect a removed item (409 ITEM_ARCHIVED unless restore is intended). Broadcasts a menu_item_updated realtime event. Idempotent (converges).
Store the item belongs to (also authorises the merchant).
Item name (required; max 120 chars).
Price in pence (required; 0..10,000,000).
A menu_items row (write result, raw DB shape).
curl -X PATCH "https://www.membber.com/api/v1/menu-items/b9bf0b8e-0000-4000-8000-d0c5000000b9" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"name": "Example name",
"price_pence": 1500
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.PATCH("/api/v1/menu-items/{itemId}", {
params: { path: { itemId: "b9bf0b8e-0000-4000-8000-d0c5000000b9" } },
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name",
price_pence: 1500
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.updateMenuItem(
path: .init(itemId: "b9bf0b8e-0000-4000-8000-d0c5000000b9"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name",
pricePence: 1500
))
).ok.body.json
print(response){
"item": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"name": "Example name",
"price_pence": 1500,
"currency": "GBP",
"is_available": true,
"checkout_enabled": true
}
}