GET https://api.fire.rest/api/v1/fire/external/stores/550e8400-e29b-41d4-a716-446655440000/menu?channel=KIOSK&fulfillmentType=DINE_IN
x-api-key: <your_api_key>
{
"success": true,
"data": {
"menu": {
"list": {
"listId": "812-KIOSK-DINE_IN",
"listName": "KIOSK - Store 812",
"storeId": "aa11bb22-0000-4000-8000-000000000002",
"storeName": "Quicentro",
"channelId": "cc33dd44-0000-4000-8000-000000000009",
"channelReferenceName": "DINE_IN",
"timezone": "America/Guayaquil"
},
"categories": [
{
"productCategoryId": "cat_001",
"name": "Burgers",
"assignedAt": "2026-09-20T12:00:00Z",
"productListing": [ { "productId": "prod_001", "position": 1 } ]
}
],
"products": [
{
"productId": "prod_001",
"name": "Classic Burger",
"type": "PRODUCTO",
"active": true,
"priceInfo": { "price": 4.5 },
"productModifiers": [ { "modifierId": "mod_001", "position": 1 } ]
},
{
"productId": "prod_size_small",
"name": "Small",
"type": "MODIFIER",
"active": true,
"priceInfo": { "price": 0 },
"productModifiers": []
},
{
"productId": "prod_size_large",
"name": "Large",
"type": "MODIFIER",
"active": true,
"priceInfo": { "price": 0.5 },
"productModifiers": []
}
],
"modifierGroups": [
{
"modifierId": "mod_001",
"modifier": "Choose your size",
"minOptions": 1,
"maxOptions": 1,
"type": "RADIO",
"modifierOptions": [
{ "optionId": "opt_001", "productId": "prod_size_small", "name": "Small", "position": 1 },
{ "optionId": "opt_002", "productId": "prod_size_large", "name": "Large", "position": 2 }
]
}
]
},
"sync": {
"status": "FAILED",
"generatedAt": "2026-09-29T09:00:00Z",
"syncedAt": "2026-09-28T10:00:04Z"
}
}
}
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "channel and fulfillmentType are required"
}
{
"success": false,
"error": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
{
"success": false,
"error": "FORBIDDEN",
"message": "API key does not have required scope: menu:read"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "Store not found"
}
{
"success": false,
"error": "MENU_NOT_AVAILABLE",
"message": "This terna has no menu available"
}
API
Get menu
Read the last generated menu of a store’s terna (channel × fulfillment type), with its sync status.
GET
/
api
/
v1
/
fire
/
external
/
stores
/
{storeId}
/
menu
GET https://api.fire.rest/api/v1/fire/external/stores/550e8400-e29b-41d4-a716-446655440000/menu?channel=KIOSK&fulfillmentType=DINE_IN
x-api-key: <your_api_key>
{
"success": true,
"data": {
"menu": {
"list": {
"listId": "812-KIOSK-DINE_IN",
"listName": "KIOSK - Store 812",
"storeId": "aa11bb22-0000-4000-8000-000000000002",
"storeName": "Quicentro",
"channelId": "cc33dd44-0000-4000-8000-000000000009",
"channelReferenceName": "DINE_IN",
"timezone": "America/Guayaquil"
},
"categories": [
{
"productCategoryId": "cat_001",
"name": "Burgers",
"assignedAt": "2026-09-20T12:00:00Z",
"productListing": [ { "productId": "prod_001", "position": 1 } ]
}
],
"products": [
{
"productId": "prod_001",
"name": "Classic Burger",
"type": "PRODUCTO",
"active": true,
"priceInfo": { "price": 4.5 },
"productModifiers": [ { "modifierId": "mod_001", "position": 1 } ]
},
{
"productId": "prod_size_small",
"name": "Small",
"type": "MODIFIER",
"active": true,
"priceInfo": { "price": 0 },
"productModifiers": []
},
{
"productId": "prod_size_large",
"name": "Large",
"type": "MODIFIER",
"active": true,
"priceInfo": { "price": 0.5 },
"productModifiers": []
}
],
"modifierGroups": [
{
"modifierId": "mod_001",
"modifier": "Choose your size",
"minOptions": 1,
"maxOptions": 1,
"type": "RADIO",
"modifierOptions": [
{ "optionId": "opt_001", "productId": "prod_size_small", "name": "Small", "position": 1 },
{ "optionId": "opt_002", "productId": "prod_size_large", "name": "Large", "position": 2 }
]
}
]
},
"sync": {
"status": "FAILED",
"generatedAt": "2026-09-29T09:00:00Z",
"syncedAt": "2026-09-28T10:00:04Z"
}
}
}
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "channel and fulfillmentType are required"
}
{
"success": false,
"error": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
{
"success": false,
"error": "FORBIDDEN",
"message": "API key does not have required scope: menu:read"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "Store not found"
}
{
"success": false,
"error": "MENU_NOT_AVAILABLE",
"message": "This terna has no menu available"
}
Coming soon. The design is closed but this endpoint is not implemented yet. This page
describes the agreed contract so integrators can plan against it ahead of release.
menu.updated webhook. Use
List menus to discover which ternas of a store currently have one.
Authentication
string
required
Your Fire API key with the
menu:read scope. The key must be vendor-scoped (account + vendor
binding) — keys without a vendorId are rejected with 403.Path parameters
string
required
Store UUID (
stores.id).Query parameters
There is no default terna — Fire never guesses one on your behalf. Both parameters are required;
missing either one returns
400.string
required
Sales channel code (e.g.
KIOSK). Compared case-insensitively.string
required
Fulfillment type code (e.g.
DINE_IN, TAKEAWAY). Compared case-insensitively.Request
GET https://api.fire.rest/api/v1/fire/external/stores/550e8400-e29b-41d4-a716-446655440000/menu?channel=KIOSK&fulfillmentType=DINE_IN
x-api-key: <your_api_key>
Response
object
Same shape as
data.menu in the menu.updated
webhook — list, categories, products, modifierGroups — with the same enrichment
aggregators receive today (internal ids in list.storeId / list.channelId,
categories[].assignedAt). See that page for the full field reference.Show known gaps
Show known gaps
productModifiers[] and modifierGroups[].modifierOptions[] do not yet carry active or
assignedAt — the same gap the webhook payload has today. This endpoint returns exactly what
is emitted; the gap closes on the emitter side, and this response inherits the fix.Same shape for X-MART-type channels too.
KIOSK (authType: XMART_LOGIN — see
channel.updated) is one of them: its stored payload
additionally carries the store number and the external channel id, already folded into list
above.object
Show sync
Show sync
string
SYNCED | FAILED | PENDING — the last delivery attempt of this menu version.string
ISO 8601 timestamp of this menu version.
string | null
ISO 8601 timestamp of the last successful delivery.
null if it never synced. See syncedAt semantics.{
"success": true,
"data": {
"menu": {
"list": {
"listId": "812-KIOSK-DINE_IN",
"listName": "KIOSK - Store 812",
"storeId": "aa11bb22-0000-4000-8000-000000000002",
"storeName": "Quicentro",
"channelId": "cc33dd44-0000-4000-8000-000000000009",
"channelReferenceName": "DINE_IN",
"timezone": "America/Guayaquil"
},
"categories": [
{
"productCategoryId": "cat_001",
"name": "Burgers",
"assignedAt": "2026-09-20T12:00:00Z",
"productListing": [ { "productId": "prod_001", "position": 1 } ]
}
],
"products": [
{
"productId": "prod_001",
"name": "Classic Burger",
"type": "PRODUCTO",
"active": true,
"priceInfo": { "price": 4.5 },
"productModifiers": [ { "modifierId": "mod_001", "position": 1 } ]
},
{
"productId": "prod_size_small",
"name": "Small",
"type": "MODIFIER",
"active": true,
"priceInfo": { "price": 0 },
"productModifiers": []
},
{
"productId": "prod_size_large",
"name": "Large",
"type": "MODIFIER",
"active": true,
"priceInfo": { "price": 0.5 },
"productModifiers": []
}
],
"modifierGroups": [
{
"modifierId": "mod_001",
"modifier": "Choose your size",
"minOptions": 1,
"maxOptions": 1,
"type": "RADIO",
"modifierOptions": [
{ "optionId": "opt_001", "productId": "prod_size_small", "name": "Small", "position": 1 },
{ "optionId": "opt_002", "productId": "prod_size_large", "name": "Large", "position": 2 }
]
}
]
},
"sync": {
"status": "FAILED",
"generatedAt": "2026-09-29T09:00:00Z",
"syncedAt": "2026-09-28T10:00:04Z"
}
}
}
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "channel and fulfillmentType are required"
}
{
"success": false,
"error": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
{
"success": false,
"error": "FORBIDDEN",
"message": "API key does not have required scope: menu:read"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "Store not found"
}
{
"success": false,
"error": "MENU_NOT_AVAILABLE",
"message": "This terna has no menu available"
}
Notes
The last generated menu, even if it never synced
Fire stores the menu payload before sending it, and every attempt overwrites the previous one. This endpoint returns that last version regardless of whether the send reached the channel — thesync block tells you whether it did.
Example: on Monday KIOSK/DINE_IN syncs fine. On Tuesday prices go up and the send fails.
Wednesday’s GET returns Tuesday’s version with sync.status: FAILED and sync.syncedAt still
pointing at Monday.
Out-of-stock is recalculated at read time
The stored payload’sactive reflects the out-of-stock state at the moment the menu was
generated. A product marked out-of-stock afterwards reaches the channel through its own webhook,
not by rewriting the stored menu. This endpoint recalculates active against the out-of-stock
state at the moment of the request, for products[].active and for combo option-products.
Example, in both directions: the menu generates at 10:00 with an item out of stock. At 11:00 the
mark-down expires and the webhook reactivates the item on the channel. A GET at 11:05 shows it
active, matching the channel — not out of stock, which is what the stored payload alone would show.
syncedAt semantics
sync.syncedAt means “last successful delivery,” consistently across every channel type,
including X-MART ones. A failed send never advances it.
Terna without a menu — 404 MENU_NOT_AVAILABLE
If the terna exists but has no menu or price list assigned, the response is 404 MENU_NOT_AVAILABLE — distinct from the 404 used when the store itself doesn’t exist or belongs
to another tenant. The store is already validated against your key before this check runs, so this
response never leaks another tenant’s data.
Empty send — also 404 MENU_NOT_AVAILABLE
When the flattening step produces zero sellable products, the send fails without ever reaching the
channel — but the stored payload still has products: []. This endpoint treats that the same as a
terna with no menu: 404 MENU_NOT_AVAILABLE, rather than a 200 with an empty menu. An empty menu
here would be indistinguishable from “this store sells nothing,” which is not what happened — the
menu never reached the channel. List menus still shows the terna,
with syncStatus: FAILED, so the problem is visible.
Related
List menus
Discover which ternas of a store have a generated menu.
menu.updated
The webhook this endpoint mirrors — full field reference for
data.menu.Get store
Read a single store by id.

