JimmyJohns API endpoint
Returns one Jimmy John's restaurant's full menu as a category tree: every category and its products, with name, description, calorie range, base cost and image. restaurant_id comes from GET /jimmy-johns/nearby. Many sandwiches price entirely through a size selection rather than a base cost, so cost is commonly 0 for those items -- see GET /jimmy-johns/modifiers for the real per-size price.
/jimmy-johns/menuReturns one Jimmy John's restaurant's full menu as a category tree — every category and its products — using Jimmy John's own Olo-backed ordering API. restaurant_id comes from /jimmy-johns/nearby.
Query parameters:
restaurant_id (required) — Olo restaurant id from a /jimmy-johns/nearby result.Response includes restaurant_id, categories[], category_count, product_count, source_url, and fetched_at. Each category has category_id, name, and products[]. Each product has product_id, chain_product_id, name, description, short_description, cost, base_calories, max_calories, and image_url.
Notable response behavior:
cost is 0 for those items — see /jimmy-johns/modifiers for the real per-size price. Combos and flat-priced items (cookies, drinks) carry a real cost.base_calories and max_calories bound the calorie range across an item's size/customization options and arrive as strings (e.g. Jimmy John's own site renders 370-650 with a separator), so they are not coerced to a number here.chain_product_id identifies an item across every Jimmy John's restaurant; product_id is specific to this restaurant's own menu.restaurant_id with no active menu returns a 404.| Field | Filled in, of 20 checked | Values in the sample |
|---|---|---|
| category_id | 20 | |
| name | 20 | “What’s New” and 16 other values |
| products | 20 | median 6 entries |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| restaurant_id | integer | Yes | Olo restaurant id from /jimmy-johns/nearby | 67182 | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/jimmy-johns/menu?restaurant_id=67182" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"restaurant_id": 67182,
"categories": [
{
"category_id": 69933,
"name": "Originals",
"products": [
{
"product_id": 33276056,
"chain_product_id": 353441,
"name": "#1 The Pepe®",
"description": "HAM, PROVOLONE, lettuce, tomato & mayo",
"cost": 0,
"base_calories": "370",
"max_calories": "650",
"image_url": "https://olo-images-live.imgix.net/49/497e4a5114b6455fa74aa9b808dbe499.png"
}
]
}
],
"category_count": 20,
"product_count": 180,
"source_url": "https://jj.ordering.api.olo.com/v1.1/restaurants/67182/menu",
"fetched_at": "2026-09-02T00:00:00Z"
}
}Request schema
No body schema
Response schema
#/definitions/jimmyjohns.menuResponseDoc
| 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 | jimmyjohns.MenuResponse | No | ||||
| data.categories | array | No | ||||
| data.categories[].category_id | integer | No | 69933 | |||
| data.categories[].name | string | No | Originals | |||
| data.categories[].products | array | No | ||||
| data.categories[].products[].base_calories | string | No | 370 | BaseCalories and MaxCalories bound the calorie range across this item's size/customization options. Both arrive from upstream as strings (e.g. a "-" separator is rendered client-side), so they are kept as strings rather than coerced to a number. | ||
| data.categories[].products[].chain_product_id | integer | No | 353441 | ChainProductID identifies this item across every Jimmy John's restaurant; ProductID is specific to this restaurant's menu. | ||
| data.categories[].products[].cost | number | No | 8.69 | Cost is the base price. Many sandwiches price entirely through a size modifier rather than a base cost, so this is commonly 0 -- it is not a parsing gap. | ||
| data.categories[].products[].description | string | No | HAM, PROVOLONE, lettuce, tomato & mayo | |||
| data.categories[].products[].image_url | string | No | ||||
| data.categories[].products[].max_calories | string | No | 650 | |||
| data.categories[].products[].name | string | No | #1 The Pepe® | |||
| data.categories[].products[].product_id | integer | No | 33276056 | |||
| data.categories[].products[].short_description | string | No | ||||
| data.category_count | integer | No | 20 | |||
| data.fetched_at | string | No | ||||
| data.product_count | integer | No | 180 | |||
| data.restaurant_id | integer | No | 67182 | |||
| data.source_url | string | No | ||||
| 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/jimmy-johns/menu?restaurant_id=67182" \
-H "x-api-key: $CRAWLORA_API_KEY"