Papa John's API endpoint
Use Crawlora's Papa John's International Stores API to extract supported public Papa John's data as structured JSON. This page includes request parameters, cURL examples, response schema, error behavior, credit cost, and a Playground link for testing before integration.
/papajohns/intl/storesReturns Papa John's restaurants in one of six international markets: Chile, Costa Rica, Guatemala, Panama, Portugal, and Spain -- either every restaurant near a coordinate, or one known restaurant looked up by id. Each restaurant carries its address, coordinates, phone, per-weekday opening hours split by fulfillment channel, accepted payment methods, delivery zones with their minimum-order and free-delivery thresholds, and live delivery/pickup open flags. Restaurants come back ranked by distance with no radius limit, five at a time by default; page and limit walk the rest, and the response reports total_count, the market's whole restaurant total. The returned id is what GET /papajohns/intl/menu prices against, and menu_id is what GET /papajohns/intl/ingredients reads. This covers those six markets only -- for India use GET /papajohns/india/stores, and for the US and Canada use GET /papajohns/directory, GET /papajohns/store, or GET /papajohns/nearby. Developers commonly use this endpoint for data enrichment, monitoring, research dashboards, internal automation, and agent-native workflows that need repeatable structured public web data. Authentication uses the documented Crawlora headers, and usage is metered with the credit cost shown on this page.
Request parameters are generated from the active endpoint catalog. Required values must be sent before Crawlora can call the upstream public web data source.
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| market | string | Yes | Market. One of: chile, costa-rica, guatemala, panama, portugal, spain Allowed values: chile, costa-rica, guatemala, panama, portugal, spain | ||
| store_id | string | No | Look up one known restaurant by id instead of searching a coordinate. Supply either store_id, or both latitude and longitude. | ||
| latitude | string | No | Latitude to search around. Required unless store_id is supplied. | ||
| longitude | string | No | Longitude to search around. Required unless store_id is supplied. | ||
| fulfillment | string | No | One of: delivery (default, every nearby restaurant), pickup (only restaurants accepting pickup orders). Ignored when store_id is supplied. Allowed values: delivery, pickup | ||
| page | integer | No | One-based page of the distance-ranked restaurants. Ignored for a store_id lookup and for pickup, neither of which is paginated. Minimum: 1. | ||
| limit | integer | No | Restaurants per page, 1-100. Ignored for a store_id lookup and for pickup, neither of which is paginated. Minimum: 1. Maximum: 100. | ||
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/papajohns/intl/stores?market=chile&fulfillment=delivery&page=1&limit=10" \ -H "x-api-key: $CRAWLORA_API_KEY"
Send your scraping API key in the x-api-key header. Use the console API Keys page to rotate or select the active key.
Endpoint usage is metered in credits. The plan prices, included credits, limits, and overage rates below match the active backend billing configuration.
| Plan | Price | Included credits | Daily cap | Rate limit | Overage |
|---|---|---|---|---|---|
| Free | $0/mo | 2,000 | 500 daily credits | 5/min | No overage |
| Starter | $9/mo | 20,000 | 5,000 daily credits | 15/min | $0.75/1,000 overage credits when enabled |
| Growth | $29/mo | 100,000 | 25,000 daily credits | 45/min | $0.45/1,000 overage credits when enabled |
| Pro | $79/mo | 400,000 | No daily cap | 120/min | $0.30/1,000 overage credits |
| Business | $199/mo | 1,200,000 | No daily cap | 300/min | $0.20/1,000 overage credits |
| Enterprise | $499/mo | 5,000,000 | No daily cap | 1,000/min | $0.12/1,000 overage credits |
This endpoint is executed through Crawlora's managed scraping infrastructure.
- The `id` on each restaurant is what [`/papajohns/intl/menu`](papajohns-intl-menu.md) prices against, and `menu_id` is what [`/papajohns/intl/ingredients`](papajohns-intl-ingredients.md) reads. Several restaurants usually share one `menu_id`. - `hours` has one entry per weekday per fulfillment channel, with `dispatch_method` naming the channel. Times are wall-clock in the restaurant's own local time; upstream's placeholder date is dropped. - `payment_methods` lists only the methods the restaurant actually accepts. - `delivery_zones` carries each tier's delivery fee and its minimum-order and free-delivery thresholds where the market publishes them. - A restaurant that is currently closed is still returned, with `delivery_open`/`pickup_open` false. - A coordinate search ranks the market's restaurants by distance and has no radius cut-off, so any coordinate returns the nearest ones rather than nothing. `count` is how many this response carries, and `page`, `total_pages` and `total_count` describe the rest of the ranking, so a first page is distinguishable from the whole of it. `total_count` is the market's entire restaurant total rather than a match count — for the same reason there is no radius cut-off — so it is the same for every coordinate in a market. - Raising `limit` returns more of the same ranking in one call rather than a different one: the first five of `limit=100` are the same five, in the same order, that the default returns. Pages carry no duplicates. - Asking for a `page` past the last one returns a `404` naming the last page, rather than an empty list. `page` below `1` is rejected as a `400`. - An empty restaurant list is never reported as a successful search. If the market has restaurants but none could be read, the request fails with a `503`; if the market carries no restaurants at all, it returns a `404`. - A `store_id` lookup ignores `fulfillment` and returns exactly one store, or a `404` if the market has no such restaurant. It has no search origin, so `latitude`, `longitude` and `fulfillment` are omitted from the response rather than reported as `0` — `0,0` is itself a real coordinate. - Supplying neither `store_id` nor a coordinate pair returns a `400`, as does an unknown `market` or `fulfillment` or an out-of-range coordinate. Example response: ```json {"code":200,"msg":"OK","data":{"market":"spain","fulfillment":"delivery","latitude":40.4168,"longitude":-3.7038,"stores":[{"id":9,"name":"Vallejo Nájera","menu_id":8,"address":"Paseo de Juan Antonio Vallejo - Nájera Botas, 25, 28005","city":"Madrid","region":"Madrid","phone":"+34910493017","latitude":40.401686,"longitude":-3.708348,"order_method":"both","delivery_open":true,"pickup_open":true,"delivery_wait_minutes":30,"pickup_wait_minutes":15,"future_orders":true,"external_delivery":true,"payment_methods":["apple_pay","bizum","cash","credit","direct_click_to_pay","google_pay","paypal"],"delivery_zones":[{"name":"La más fresca 6,99€","delivery_price":0}],"hours":[{"day":"monday","dispatch_method":"in_store","opens":"12:00:00","closes":"23:59:59"}]}],"count":5,"page":1,"total_pages":20,"total_count":97,"source_url":"https://api.papajohns.es/v1/stores?latitude=40.4168&longitude=-3.7038","fetched_at":"2026-09-06T09:00:00Z"}} ```
Crawlora does not silently return bad data when the upstream page cannot be used.
| Status | Common failure case |
|---|---|
| 400 | Invalid input or missing required parameter |
| 429 | Plan or endpoint rate limit exceeded |
| 500 | Internal execution error |
| 502 | Upstream platform failed, returned unusable HTML, or served a challenge page that could not be resolved |
When possible, Crawlora returns structured error context so your integration can retry, back off, or inspect the request.
| 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 |
{
"code": 200,
"msg": "OK",
"data": {
"market": "spain",
"fulfillment": "delivery",
"latitude": 40.4168,
"longitude": -3.7038,
"stores": [
{
"id": 9,
"name": "Vallejo Nájera",
"menu_id": 8,
"address": "Paseo de Juan Antonio Vallejo - Nájera Botas, 25, 28005",
"city": "Madrid",
"region": "Madrid",
"phone": "+34910493017",
"latitude": 40.401686,
"longitude": -3.708348,
"order_method": "both",
"delivery_open": true,
"pickup_open": true,
"delivery_wait_minutes": 30,
"pickup_wait_minutes": 15,
"future_orders": true,
"external_delivery": true,
"payment_methods": [
"apple_pay",
"bizum",
"cash",
"credit",
"direct_click_to_pay",
"google_pay",
"paypal"
],
"delivery_zones": [
{
"name": "La más fresca 6,99€",
"delivery_price": 0
}
],
"hours": [
{
"day": "monday",
"dispatch_method": "in_store",
"opens": "12:00:00",
"closes": "23:59:59"
}
]
}
],
"count": 5,
"page": 1,
"total_pages": 20,
"total_count": 97,
"source_url": "https://api.papajohns.es/v1/stores?latitude=40.4168&longitude=-3.7038",
"fetched_at": "2026-09-06T09:00:00Z"
}
}Request schema
No body schema
Response schema
#/definitions/papajohns.intlStoresResponseDoc
| 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 | papajohns.IntlStoresResponse | No | ||||
| data.count | integer | No | 5 | Count is how many restaurants this response carries. | ||
| data.fetched_at | string | No | ||||
| data.fulfillment | string | No | delivery | Fulfillment, Latitude and Longitude echo a coordinate search and are absent on a store_id lookup, which has no search origin. They are omitted rather than zeroed because 0,0 is itself a real coordinate. | ||
| data.latitude | number | No | 40.4168 | |||
| data.longitude | number | No | -3.7038 | |||
| data.market | string | No | spain | |||
| data.page | integer | No | 1 | Page, TotalPages and TotalCount describe the rest of the result set, so a caller can tell a first page from the whole of it. TotalCount is the market-wide restaurant total rather than a match count, because the search has no radius cut-off -- every restaurant in the market is ranked, and this is where in that ranking the response sits. All three are absent for a store_id lookup and for pickup, neither of which upstream paginates. | ||
| data.source_url | string | No | ||||
| data.stores | array | No | ||||
| data.stores[].address | string | No | ||||
| data.stores[].city | string | No | Madrid | |||
| data.stores[].delivery_open | boolean | No | true | |||
| data.stores[].delivery_wait_minutes | integer | No | 30 | |||
| data.stores[].delivery_zones | array | No | ||||
| data.stores[].delivery_zones[].delivery_price | number | No | 0 | |||
| data.stores[].delivery_zones[].minimum_order_for_delivery | number | No | ||||
| data.stores[].delivery_zones[].minimum_order_for_free_delivery | number | No | ||||
| data.stores[].delivery_zones[].name | string | No | Zona 1 | |||
| data.stores[].external_delivery | boolean | No | true | |||
| data.stores[].future_orders | boolean | No | true | |||
| data.stores[].hours | array | No | ||||
| data.stores[].hours[].closes | string | No | 23:59:59 | |||
| data.stores[].hours[].day | string | No | monday | |||
| data.stores[].hours[].dispatch_method | string | No | in_store | DispatchMethod is the fulfillment channel this window applies to, e.g. in_store or pj_delivery. | ||
| data.stores[].hours[].opens | string | No | 12:00:00 | |||
| data.stores[].id | integer | No | 9 | |||
| data.stores[].latitude | number | No | 40.401686 | |||
| data.stores[].longitude | number | No | -3.708348 | |||
| data.stores[].map_url | string | No | ||||
| data.stores[].menu_id | integer | No | 8 | MenuID identifies the catalog this restaurant serves. Several restaurants usually share one. | ||
| data.stores[].name | string | No | Vallejo Nájera | |||
| data.stores[].order_method | string | No | both | OrderMethod is the fulfillment the restaurant supports, as upstream reports it, e.g. both, delivery, or pick_up. | ||
| data.stores[].payment_methods | array | No | PaymentMethods lists only the methods this restaurant actually accepts. | |||
| data.stores[].phone | string | No | +34910493017 | |||
| data.stores[].pickup_open | boolean | No | true | |||
| data.stores[].pickup_wait_minutes | integer | No | 15 | |||
| data.stores[].region | string | No | Madrid | |||
| data.total_count | integer | No | 97 | |||
| data.total_pages | integer | No | 20 | |||
| msg | unknown | No | Msg is the message that describes the result of the request @example "Request successful" |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/papajohns/intl/stores?market=chile&fulfillment=delivery&page=1&limit=10" \
-H "x-api-key: $CRAWLORA_API_KEY"Crawlora is designed for responsible structured public web data workflows. Customers are responsible for using Crawlora in compliance with applicable laws, third-party rights, target-platform rules, and Crawlora terms.
Read Crawlora terms