OneTablet API Documentation

createUberEatsPromotion

POST/management/promotions/createUberEatsPromotion

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 (ONE-3288); 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 (ONE-2990). 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 (ONE-3541). 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.

Request

application/json
required
  • storeIdstring

    REQUIRED. The storefront to run the promotion on, as fetchStores reports 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 UberEatsDiscount for your promoType, e.g. minBasket + discountValue for FLATOFF; percentValue + maxDiscount for PERCENTOFF; targetItemIds for BOGO; per-item items for MENU_ITEM_DISCOUNT. When present, discount.promoType must equal promoType or the request is a 400. REQUIRED for PERCENTOFF and MENU_ITEM_DISCOUNT: omitting it there is a 400.

  • budgetUberEatsPromotionBudget

    The spend ceiling. amount is an INTEGER IN MINOR UNITS — see UberEatsPromotionBudget.

  • allowUnlimitedApplyboolean

    Whether one customer may redeem repeatedly.

  • userGroupstring

    ONE-3409, ADDITIVE. Uber requires SOME user_group at create time; omit this and OneTablet defaults it to ALL_CUSTOMERS on your behalf. See UberEatsUserGroup.

    Possible values: [ALL_CUSTOMERS, FIRST_TIME_CUSTOMER]

Responses

200 — OK
  • promotionUberEatsPromotion

    The new promotion, carrying the promotionId every 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 (ONE-3382 reversed the earlier THREE-operation decision, 2026-09-24 — see the file header). fetchUberEatsPromotions (list), fetchUberEatsPromotion (get one, by id), createUberEatsPromotion and revokeUberEatsPromotion are the whole UberEats lifecycle: no update and no pause exist platform-side, and a promotion is immutable once created. fetchUberEatsPromotion is its own operation — matching the published docs site and the fetchStore / fetchOrder convention this API already follows elsewhere — rather than fetchUberEatsPromotions with one entry in promotionIds, even though the latter can answer the same question.

NAMED FOR THE PLATFORM IN THE METHOD, NOT THE PATH. The section is Promotions because DoorDash and Grubhub belong beside these, and the platforms differ materially: DoorDash exposes no promotion WRITE api to integrations at all, and Grubhub no promotions surface whatsoever — for both, promotion attribution arrives on the ORDER payload instead (see the Orders section, live today). A single fetchPromotions returning a union of three platform models would be worse for a generated client than one named operation per platform. So the path is /management/promotions and the operations name UberEats.

createUberEatsPromotion and revokeUberEatsPromotion are WRITES and are classified as such in ManagementApiKeyHook — a read-only api key is refused with 403.