McDonalds API endpoint
Returns one restaurant's full menu with real prices: item name, image and independently-priced eat-in, pickup and delivery listings, since a McDonald's restaurant genuinely sells a different catalog (and different prices) per channel -- delivery is typically marked up over eat-in/pickup, and some items are channel-exclusive. Where McDonald's publishes a curated substitute or add-on list for an item (a meal's drink upgrade, a dip-able item's sauce choices), each real alternative is included with its own eat-in/pickup price delta -- plain entree or side substitution is not covered, since McDonald's does not publish a curated candidate list for it. This is the only endpoint in this family that publishes prices; every other McDonald's endpoint's source never does. US restaurants only. The store id comes from GET /mcdonalds/restaurants' store_id field.
/mcdonalds/restaurant-menuUS restaurants only.
Query parameters:
store_id (required) — McDonald's numeric store number, from /api/v1/mcdonalds/restaurants' store_id field, e.g. 10528.An unknown or inactive store id returns a 503 rather than an empty menu: a real restaurant always has a priced menu, so zero usable items means either an unrecognized store or upstream response drift, and neither is served as a successful empty result.
Response includes store_id, currency, items[], count, source_url, and fetched_at. Each item has item_id, name, family_group (McDonald's own internal product classification, e.g. REGULAR_ENTREE — not the same category list /mcdonalds/categories returns, and not always present), image_url, up to three independent prices (eat_in_price, pickup_price, delivery_price — a channel's price is omitted entirely when that restaurant does not sell the item through that channel, rather than a 0 or null placeholder), and choices[].
choices[] lists an item's customizable components where McDonald's publishes a curated substitute or add-on list for it — a meal's drink upgrade options, or a dip-able item's sauce choices — each with options[]: item_id, name, and price_delta (the additional eat-in/pickup cost of picking that option; negative for a cheaper swap, and equal to the option's own full price for an add-on with nothing already included). choices[] is omitted for an item with no such curated list. Plain entree or side substitution is not covered — McDonald's does not publish a curated candidate list for it, unlike drink upgrades and add-on sauces.
| Field | Filled in, of 599 checked | Values in the sample |
|---|---|---|
| item_id | 500 | |
| name | 500 | “Hamburger” and 351 other values |
| family_group | 500 | “REGULAR_ENTREE” and 8 other values |
| image_url | 465 | s7d1.scene7.com |
| eat_in_price | 496 | 0 to 43.99, median 3.39 |
| pickup_price | 496 | 0 to 43.99, median 3.39 |
| delivery_price | 481 | 0 to 53.19, median 4.79 |
| choices | 80 | median 1 entry |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| store_id | string | Yes | McDonald's numeric store number, from /mcdonalds/restaurants | 10528 | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/mcdonalds/restaurant-menu?store_id=10528" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"store_id": "10528",
"currency": "$",
"items": [
{
"item_id": "5",
"name": "Big Mac®",
"family_group": "REGULAR_ENTREE",
"image_url": "https://s7d1.scene7.com/is/image/mcdonalds/DC_202408_0005-999_BigMac",
"eat_in_price": 7.29,
"pickup_price": 7.29,
"delivery_price": 8.39
},
{
"item_id": "98",
"name": "Deluxe Spicy McCrispy™ Meal",
"family_group": "REGULAR_ENTREE",
"eat_in_price": 13.59,
"pickup_price": 13.59,
"delivery_price": 16.89,
"choices": [
{
"options": [
{
"item_id": "522",
"name": "Coke®",
"price_delta": 0
},
{
"item_id": "14877",
"name": "Lemonade",
"price_delta": 0.4
}
]
}
]
}
],
"count": 563,
"source_url": "https://us-prod.api.mcd.com/us/gma/api/v1/restaurants/10528/menus",
"fetched_at": "2026-09-02T18:00:00Z"
}
}Request schema
No body schema
Response schema
#/definitions/mcdonalds.restaurantMenuResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | Code is the HTTP status code or a custom code used to indicate the result of the request @example 200 | |||
| data | mcdonalds.RestaurantMenuResponse | No | ||||
| data.count | integer | No | 563 | |||
| data.currency | string | No | $ | |||
| data.fetched_at | string | No | ||||
| data.items | array | No | ||||
| data.items[].choices | array | No | Choices lists this item's customizable components McDonald's publishes a curated substitute/add-on list for -- e.g. a meal's drink upgrade options, or a dip-able item's sauce choices -- with the live eat-in/pickup price delta for each real alternative. Present only when the upstream payload exposed at least one such choice for this item; see the package doc comment for how these are derived and the deliberate fail-closed rule behind what gets left out (in particular, plain entree/side substitution is not exposed at all -- McDonald's does not publish a curated candidate list for it, only for upgrade/add-on style choices). | |||
| data.items[].choices[].options | array | No | ||||
| data.items[].choices[].options[].item_id | string | No | 14877 | |||
| data.items[].choices[].options[].name | string | No | Lemonade | |||
| data.items[].choices[].options[].price_delta | number | No | 0.4 | PriceDelta is the additional eat-in/pickup cost of choosing this option instead of what's already included: 0 for a same-priced swap, negative for a cheaper one, and equal to the option's own full price for an add-on choice (nothing is included to offset against). | ||
| data.items[].delivery_price | number | No | 8.39 | |||
| data.items[].eat_in_price | number | No | 7.29 | |||
| data.items[].family_group | string | No | REGULAR_ENTREE | FamilyGroup is McDonald's own internal product classification (e.g. REGULAR_ENTREE, DESSERT) -- not the same category list /mcdonalds/categories returns, and not always present. | ||
| data.items[].image_url | string | No | ||||
| data.items[].item_id | string | No | 5 | |||
| data.items[].name | string | No | Big Mac® | |||
| data.items[].pickup_price | number | No | 7.29 | |||
| data.source_url | string | No | ||||
| data.store_id | string | No | 10528 | |||
| msg | unknown | No | Msg is the message that describes the result of the request @example "Request successful" |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 404 | Not Found | #/definitions/app.Response |
| 429 | Too Many Requests | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/mcdonalds/restaurant-menu?store_id=10528" \
-H "x-api-key: $CRAWLORA_API_KEY"