Popeyes API endpoint
Returns a page of Popeyes' promotional offers/deals catalog -- named value deals (e.g. "3Pc Signature Chicken for $5"), percentage-off combos, and paper coupons. This is CMS content describing the offer catalog, the same kind of public data /popeyes/menu already reads from -- not a personalized or store-specific list, and not account/loyalty state. A missing price does not mean free; a price of 0 means the offer's discount is not expressed as a flat price (see offer_tag/name instead, e.g. a percentage-off deal). requires_authentication reflects the offer's own published redemption rules, not any account state this endpoint reads. The catalog spans hundreds of entries including ones no longer running; there is no upstream "currently active" flag, so pages should be read as reference data, not a guarantee every entry is live right now.
/popeyes/offersQuery parameters:
limit (optional, default 20) — maximum offers to return, 1-100.offset (optional, default 0) — number of offers to skip, for paging through the full catalog.market (optional, default US) — restaurant market: US or CA. Each market reads its own distinct offer catalog.Response includes offers[], count, has_more, source_url, and fetched_at. has_more is a paging heuristic (true when the page returned as many offers as limit asked for) since Sanity's API for this dataset does not publish a total count. Each offer has id, name, description, section, offer_tag, redemption_type, short_code, price_cents, price, daypart, mobile_order_only, and requires_authentication.
redemption_type values observed live include STANDARD (in-app/online) and PAPER_COUPON. offer_tag values observed live include VALUE_DEAL and PERCENTAGE_OFF.
| Field | Filled in, of 20 checked | Values in the sample |
|---|---|---|
| id | 20 | |
| name | 20 | “FREE Strawberry Biscuit with Minimum $15 Spend” and 19 other values |
| description | 20 | “Receive a FREE* Strawberry Biscuit on your next order of $1…” and 19 other values |
| redemption_type | 20 | STANDARD in all 20 |
| price_cents | 19 | 0 to 3,899, median 899 |
| price | 19 | 0 to 38.99, median 8.99 |
| mobile_order_only | 20 | true in 20 of 20 |
| requires_authentication | 20 | true in 0 of 20 |
| offer_tag | 11 | LIMITED_TIME (5), NEW (3), GROUP_DEAL (1) and 2 more |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| limit | integer | No | Maximum offers to return, 1-100 (default 20) | 20 | |
| offset | integer | No | Number of offers to skip, for paging (default 0) | 0 | |
| market | string | No | Restaurant market: US (default) or CA | US | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/popeyes/offers?limit=10" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"offers": [
{
"id": "00a369e5-1b33-4d35-b153-e372e3ebf17f",
"name": "3Pc Signature Chicken for $5",
"description": "3 Piece Chicken",
"offer_tag": "VALUE_DEAL",
"redemption_type": "STANDARD",
"short_code": "8438",
"price_cents": 500,
"price": 5,
"mobile_order_only": false,
"requires_authentication": false
}
],
"count": 1,
"has_more": true,
"source_url": "https://czqk28jt.apicdn.sanity.io/v1/graphql/prod_plk_us/default",
"fetched_at": "2026-09-02T00:00:00Z"
}
}Request schema
No body schema
Response schema
#/definitions/popeyes.offersResponseDoc
| 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 | popeyes.OffersResponse | No | ||||
| data.count | integer | No | 20 | |||
| data.fetched_at | string | No | ||||
| data.has_more | boolean | No | true | HasMore is true when this page returned as many offers as Limit asked for, meaning more may exist at the next Offset. Sanity's GraphQL API for this dataset does not publish a total count for allSystemwideOffers, so this is a paging heuristic, not an exact total. | ||
| data.offers | array | No | ||||
| data.offers[].daypart | array | No | Daypart restricts the offer to specific times of day (e.g. ["allDay"]), when Popeyes publishes a restriction. | |||
| data.offers[].description | string | No | 3 Piece Chicken | Description is the offer's own short copy (e.g. what's included), when Popeyes publishes one. | ||
| data.offers[].id | string | No | 00a369e5-1b33-4d35-b153-e372e3ebf17f | |||
| data.offers[].mobile_order_only | boolean | No | MobileOrderOnly is true when the offer is only redeemable through Popeyes' own mobile ordering flow. | |||
| data.offers[].name | string | No | 3Pc Signature Chicken for $5 | |||
| data.offers[].offer_tag | string | No | VALUE_DEAL | OfferTag is Popeyes' own short badge for the offer's kind (e.g. VALUE_DEAL, PERCENTAGE_OFF), when published. | ||
| data.offers[].price | number | No | 5 | |||
| data.offers[].price_cents | integer | No | 500 | PriceCents/Price are the offer's flat price when it has one (e.g. "3Pc Signature Chicken for $5" prices at 500 cents). A value of 0 does not mean free -- it means the offer's discount is not expressed as a flat price (see OfferTag/Name instead, e.g. a percentage-off or BOGO deal). | ||
| data.offers[].redemption_type | string | No | STANDARD | RedemptionType is how the offer is redeemed -- observed live values include STANDARD (in-app/online) and PAPER_COUPON. | ||
| data.offers[].requires_authentication | boolean | No | RequiresAuthentication is true when the offer's own published rules mark it as needing a signed-in Popeyes Rewards account to redeem -- derived from the offer's rules, not assumed. This build does not call any account/loyalty-scoped API; it only reports what the offer's own public CMS record says about itself. | |||
| data.offers[].section | string | No | For Two | Section is the offer catalog's own grouping (e.g. "For Two"), when Popeyes assigns one -- most offers do not have one. | ||
| data.offers[].short_code | string | No | 8438 | ShortCode is the offer's own promo/redemption code, when published. | ||
| 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 |
| 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/popeyes/offers?limit=10" \
-H "x-api-key: $CRAWLORA_API_KEY"