Create an UberEats promotion
Create a promotion on one of your UberEats storefronts.
If Uber Eats refuses the call (for example, because the promotions scope is withdrawn), it fails with a typed dependency error naming the scope, and nothing is spent.
This spends money on a live storefront and cannot be undone — only revoked, which stops it going forward and refunds nothing. It is also NOT idempotent: read CreateUberEatsPromotionRequest's notes on retries and on immutability before you write the calling code, not after.
Failures beyond the document-wide codes: 403 when the api key is read-only; 404 when storeId is not a storefront of your organization — an unknown id and another tenant's id are indistinguishable by design; 400 when a MENU_ITEM_DISCOUNT item sets discountValue or has no percentValue, because Uber Eats discounts a menu item by percentage only; 400 when a PERCENTOFF or MENU_ITEM_DISCOUNT promotion has no discount, when a PERCENTOFF discount has no percentValue, when a MENU_ITEM_DISCOUNT lists no items, or when any percentValue is not a whole number from 1 to 100. Each 400 names the field.
One more 400 names no field: when Uber Eats itself refuses the promotion, for a limit only Uber Eats enforces (for example an unknown userGroup or a budget period it does not offer), the call fails with 400 and errorCode (also subType) bad_request.uber_eats_refused. Its message is Uber Eats' own reason, relayed as is, and nothing is created. This 400 is final: fix the request, do not retry it unchanged.
NOT safe to retry: this operation changes state and is not idempotent.
Request
- storeIdstring
REQUIRED. The storefront to run the promotion on, as
fetchStoresreports it. - promoTypestring
REQUIRED. The promotion mechanic — see
UberEatsPromoType.Possible values: [FLATOFF, PERCENTOFF, BOGO, FREEITEM_MINBASKET, MENU_ITEM_DISCOUNT, FREEDELIVERY] - startsAtstring<date-time>
REQUIRED. When the promotion starts running.
- endsAtstring<date-time>
REQUIRED. When the promotion stops running. Must be after
startsAt. - externalPromotionIdstring
Your reference for this promotion; echoed back on order-level attribution.
- discountobject
Mechanic-specific parameters — the branch of
UberEatsDiscountfor yourpromoType, e.g.minBasket+discountValueforFLATOFF;percentValue+maxDiscountforPERCENTOFF;targetItemIdsforBOGO; per-itemitemsforMENU_ITEM_DISCOUNT. When present,discount.promoTypemust equalpromoTypeor the request is a400. REQUIRED forPERCENTOFFandMENU_ITEM_DISCOUNT: omitting it there is a400. - budgetUberEatsPromotionBudget
The spend ceiling.
amountis an INTEGER IN MINOR UNITS — seeUberEatsPromotionBudget. - allowUnlimitedApplyboolean
Whether one customer may redeem repeatedly.
- userGroupstring
Which customers the promotion is offered to. Omit it and OneTablet uses
ALL_CUSTOMERSon your behalf. SeeUberEatsUserGroup.Possible values: [ALL_CUSTOMERS, FIRST_TIME_CUSTOMER]
{
"storeId": "00000000-0000-0000-0000-000000000000",
"promoType": "FLATOFF",
"startsAt": "2026-01-01T00:00:00Z",
"endsAt": "2026-01-01T00:00:00Z",
"externalPromotionId": "00000000-0000-0000-0000-000000000000",
"discount": {},
"budget": {
"amount": 50,
"unlimited": true,
"period": "WEEKLY"
},
"allowUnlimitedApply": true,
"userGroup": "ALL_CUSTOMERS"
}Responses
Headers
- x-mealco-tx-idstringoptional
The correlation id for this call, echoed on every response — a 200 exactly as much as a 400, 401 or 500. Quote it when reporting a problem and we can find every log line for the request, in every service it touched. You may also send your own x-mealco-tx-id on the request and we adopt it, so your correlation id becomes ours. Not marked required for one reason: a request whose JSON body is malformed is rejected before it reaches an operation, so no id exists yet and that single response carries neither this header nor the txId field of the error body. Everything that reaches an operation carries it.
- promotionUberEatsPromotion
The new promotion, carrying the
promotionIdevery later call takes.
About Promotions
Promotions on the connected delivery platforms. Organization-scoped like every other section: the organization is the one the API key authenticates and no request field can name another.
Four operations cover the whole Uber Eats promotion lifecycle: fetchUberEatsPromotions (list), fetchUberEatsPromotion (get one, by id), createUberEatsPromotion and revokeUberEatsPromotion. There is no update and no pause on the platform, so a promotion is immutable once created.
The operations are named for the platform because the platforms differ materially: DoorDash exposes no promotion write API to integrations, and Grubhub no promotions surface at all — for both, promotion attribution arrives on the order instead (see the Orders section).
createUberEatsPromotion and revokeUberEatsPromotion are writes — a read-only API key is refused with 403.
Money is an integer in the currency's minor unit everywhere in this section — 1250 is $12.50.