Skip to content

Uber Eats Integration Setup

Overview

Uber Eats is a food delivery platform. This integration allows you to receive Uber Eats orders directly in Upvendo and manage them alongside your other orders. The integration is location-scoped -- each Uber Eats store is linked to a specific Upvendo location. Menu data is pushed from Upvendo to Uber Eats, and orders flow from Uber Eats into Upvendo via webhooks.

Integration Type: Third-party delivery channel (location-scoped) Sync Direction: Menu is one-way (Upvendo to Uber Eats); Orders are one-way (Uber Eats to Upvendo) Payment Handling: Uber Eats handles all customer payments. You receive payouts from Uber Eats directly. Authentication: Two-step OAuth -- user authorization code flow (for POS provisioning) plus client credentials flow (for API operations)


Purpose

The Uber Eats integration serves restaurants that want to:

  • Receive Uber Eats orders inside the Upvendo back-office and kitchen workflow
  • Push their Upvendo menu (items, categories, modifiers, prices, schedules) to Uber Eats
  • Manage order acceptance and preparation from a single system
  • Link specific Uber Eats stores to specific Upvendo locations

Key Concepts

ConceptDescription
Store IDUber Eats' identifier for a specific restaurant store. Selected from a list after OAuth authorization.
User Access TokenObtained via OAuth authorization code flow. Used for POS provisioning and store list retrieval. Stored per vendor.
Client Access TokenObtained via client credentials flow. Used for menu sync, order management, and API calls.
Refresh TokenUsed to refresh the user access token when it expires.
POS ProvisioningThe process of linking an Upvendo location to an Uber Eats store via the /pos_data endpoint.
Third-Party Integration RecordInternal Upvendo record storing credentials, sync status, and settings. Provider is uber_eats.
Uber Eats Credential RecordA separate record (per vendor) storing the user access token, refresh token, and expiry.
Integrator Brand IDSet to upvendo_brand during POS provisioning. Identifies Upvendo as the integrator.

Prerequisites

1. Uber Eats Partner Account

  • Active Uber Eats for Merchants account
  • Restaurant approved on Uber Eats platform
  • Access to Uber Eats Manager

2. Upvendo Environment Variables

The backend requires these environment-level secrets (configured by the Upvendo team):

  • UBER_EATS_CLIENT_ID -- OAuth application client ID
  • UBER_EATS_CLIENT_SECRET -- OAuth application client secret
  • UBER_EATS_REDIRECT_URI -- Redirect URI for OAuth callback
  • Uber Eats webhook secret (for webhook verification)

3. Location Configuration

  1. Go to Settings -> Locations
  2. Ensure location address matches Uber Eats listing
  3. Configure business hours (should match Uber Eats availability)

4. Menu Setup

  1. Menu items should be created in Upvendo first
  2. Prices can differ from in-store prices (Uber Eats often has markup)
  3. Ensure items have correct tax rates assigned (the delivery tax rate is used)
  4. Item instructions are disabled by default in the Uber Eats menu payload (disable_item_instructions: true)

Setup Steps

Step 1: Initiate OAuth Authorization

  1. Go to Settings -> Integrations -> Uber Eats
  2. Toggle Enable Uber Eats to ON
  3. If this is the first time connecting for this vendor:
    • The system redirects you to Uber Eats OAuth authorization page
    • URL: https://auth.uber.com/oauth/v2/authorize with scope eats.pos_provisioning
    • Log in to your Uber Eats account and authorize Upvendo
    • After authorization, you are redirected back to Upvendo
  4. The callback saves the user access token and refresh token
  5. A background job (UpdateUserUberLocationsJob) fetches all your Uber Eats stores

What happens behind the scenes:

  • The authorization code is exchanged for an access token and refresh token via POST https://auth.uber.com/oauth/v2/token
  • The tokens are stored in a vendor-scoped UberEatsCredential record
  • The job paginates through all Uber Eats stores and saves the store list to the credential record
  1. After OAuth completes, go back to Settings -> Integrations -> Uber Eats
  2. Select a Store from the dropdown (populated from your Uber Eats account)
  3. Choose Sandbox Mode (ON for testing, OFF for production)
  4. Click Enable

What happens behind the scenes:

  • A ThirdPartyIntegration record is created with provider uber_eats
  • The system calls Uber Eats' POS provisioning endpoint (POST /v1/eats/stores/{storeId}/pos_data) to link the store
  • The provisioning configures:
    • is_order_manager: true -- Upvendo manages orders
    • require_manual_acceptance: false -- Orders are auto-accepted by the system
    • Order release webhooks: enabled
    • Scheduled order webhooks: enabled
    • Delivery status webhooks: disabled
  • If provisioning fails, the integration record is deleted (rollback)

Step 3: Configure Order Settings

SettingRecommendedDescription
Auto-accept OrdersOFFReview orders before accepting
Print on ReceiveONAuto-print incoming orders
Sync MenuONPush menu changes to Uber Eats

Step 4: Sync Your Menu

  1. Go to Uber Eats -> Sync Menu
  2. Select the menus you want to push
  3. The system transforms your Upvendo menu and uploads it to Uber Eats

Data Sync Details

Menu sync is one-way from Upvendo to Uber Eats. It is triggered manually via the Sync Menu action. The sync sends the full menu payload to Uber Eats' Menu API at PUT /v2/eats/stores/{storeId}/menus.

What is synced:

Upvendo EntityUber Eats EntityDetails
MenuMenuTitle, category references, service availability (schedule)
Display Group (Category)CategoryTitle, entity references (items)
ItemItemTitle, description, image URL, price, tax rate, modifier group references
Modifier GroupModifier GroupTitle, modifier options, quantity constraints
ModifierItem (within modifier group)Title, description, image URL, price, tax rate, quantity overrides

Price conversion: Prices are converted from decimal to integer (smallest currency unit) by multiplying by 100.

Language handling: Uber Eats uses a translations.default structure. The default language name from the Upvendo item is used.

Schedule handling: Menu schedules are transformed into Uber Eats' service_availability format with day_of_week (lowercase day name) and time_periods (start_time/end_time).

Modifier quantity constraints:

  • is_mandatory -> sets min_permitted: 1 on each modifier option (context: MODIFIER_GROUP)
  • allow_same_modifier_more_than_one = false -> sets max_permitted: 1 per modifier option
  • allow_select_more_than_one with max_selected -> sets max_permitted at the group level
  • Single-select modifier groups get group-level max_permitted: 1

Display options: The payload includes disable_item_instructions: true, meaning customers cannot add special instructions to individual items.

Tax rates: The delivery-specific tax rate is used (not the dine-in rate).

The menu payload sent to Uber Eats is structured as follows:

json
{
  "categories": [...],
  "items": [...],
  "menus": [...],
  "modifier_groups": [...],
  "display_options": {
    "disable_item_instructions": true
  }
}

Each item includes:

  • id -- the Upvendo item/modifier ID
  • title.translations.default -- item name in the default language
  • description.translations.default -- item description
  • price_info.price -- integer in smallest currency unit
  • tax_info.tax_rate -- from the location's delivery tax rate
  • image_url -- item image URL
  • modifier_group_ids.ids -- array of modifier group IDs (for main items only)
  • quantity_info.overrides -- per-modifier-group quantity constraints (for modifier options)

Each modifier group includes:

  • id -- the Upvendo modifier group ID
  • title.translations.default -- modifier group name
  • modifier_options -- array of {id, type: "ITEM"} references
  • quantity_info.quantity -- group-level quantity constraints (e.g., max_permitted)

Store List Retrieval

The store list is fetched via the user access token from GET /v1/delivery/stores. It supports pagination via next_page_token. The results are cached in the UberEatsCredential record after OAuth completion.

POS Provisioning Details

When linking a store, the following configuration is sent to Uber Eats:

SettingValueDescription
integrator_brand_idupvendo_brandIdentifies Upvendo as the POS integrator
integrator_store_id{locationId}The Upvendo location ID
merchant_store_idupvendo_{locationId}Unique merchant-side identifier
is_order_managertrueUpvendo manages the full order lifecycle
require_manual_acceptancefalseOrders are auto-accepted
order_release_webhooksenabledReceive new order notifications
schedule_order_webhooksenabledReceive scheduled order notifications
delivery_status_webhooksdisabledDriver status updates not tracked
allow_single_use_items_requestsfalseSingle-use item requests not allowed
allow_special_instruction_requestsfalseSpecial instructions not allowed

Webhook Events

Uber Eats sends order-related webhooks to Upvendo. These are received at POST /webhook/uber-eats and verified by the verify.uber-eats-webhook middleware.

Webhook Flow

Uber Eats sends webhook
        |
UberEatsWebhookOrchestrator
        |
UberEatsWebhookService.handleEvent()
        |
Matches by store_id (from meta.user_id) -> finds Upvendo location
        |
Routes by event_type -> dispatches appropriate job

Event Types

Event TypeJob DispatchedDescription
orders.notificationProcessUberEatsOrderNotificationJobNew order placed. Fetches full order details, creates ThirdPartyTransaction and TransactionItems, auto-accepts the order.
orders.scheduled.notificationProcessUberEatsScheduledNotificationJobScheduled order notification. Processes similarly to regular orders.
orders.cancelProcessUberEatsCancelNotificationJobOrder cancelled. Deletes the ThirdPartyTransaction and marks TransactionItems as done.

All webhook processing is asynchronous -- jobs are dispatched to the queue and processed in the background. Each job implements ShouldBeUnique using the resource_id (order ID) to prevent duplicate processing.

Order Processing Details (orders.notification)

When a new order webhook arrives:

  1. The full order is fetched from Uber Eats API via GET /v1/delivery/order/{orderId}
  2. A ThirdPartyTransaction is created using ThirdPartyTransactionFactory::uberEatsPayloadToModel()
  3. The order is auto-accepted via POST /v1/delivery/order/{orderId}/accept
  4. For each item in the order's carts:
    • The item is matched to an Upvendo item by ID
    • Modifiers are matched from selected_modifier_groups
    • A TransactionItem is created with item snapshot, quantity, and modifier data
    • The price is taken from the Uber Eats-specific price (getPrice('uber_eats'))

Order Cancellation (orders.cancel)

When a cancellation webhook arrives:

  1. The order is fetched from Uber Eats API
  2. The ThirdPartyTransaction is deleted
  3. All associated TransactionItems are marked as is_done: true

Actions

ActionMethodEndpointDescription
Get StatusGET/uber-eats/{locationId}Returns integration status for a location
EnablePOST/uber-eats/{locationId}Enable integration (may return OAuth URL if not yet authorized)
UpdatePUT/uber-eats/{locationId}Currently not supported (returns 400 error)
DisableDELETE/uber-eats/{locationId}Remove integration and unlink store from Uber Eats
Sync MenuPOST/uber-eats/{locationId}/sync-menuPush selected menus to Uber Eats
Store ListGET/uber-eats/store-listList available Uber Eats stores for the current vendor
OAuth CallbackGET/uber-eats/callbackHandles OAuth redirect from Uber Eats (guest route)

Fields

Enable Request

FieldTypeRequiredDescription
store_idstringConditionalRequired if vendor already has OAuth tokens. The Uber Eats store ID to link.
is_sandboxbooleanNoDefault: true. Set to false for production.

Sync Menu Request

FieldTypeRequiredDescription
menu_idsarray of stringsYesUpvendo menu IDs to sync to Uber Eats

Store List Request

FieldTypeRequiredDescription
page_keystringNoPagination token for fetching next page of stores

Business Rules

  1. Two-step OAuth flow: The first time a vendor enables Uber Eats, they must complete OAuth authorization. Subsequent locations for the same vendor can use the existing tokens.
  2. One integration per location: A location can only have one active Uber Eats integration. Attempting to enable a second one throws an error.
  3. Store ID is mandatory after OAuth: Once OAuth tokens exist for the vendor, a store_id must be provided when enabling.
  4. POS provisioning on enable: Linking a store sends POS data to Uber Eats. If provisioning fails, the integration record is deleted (rollback).
  5. Unlinking on disable: Disabling the integration calls DELETE /v1/eats/stores/{storeId} to unlink the store from Upvendo.
  6. Updates not supported: The update endpoint returns a 400 error. To change settings, disable and re-enable.
  7. Order auto-acceptance: Orders received via webhook are automatically accepted (require_manual_acceptance: false during provisioning, and the order notification job calls the accept endpoint).
  8. Payment is external: Uber Eats handles all payments. No payment profile is needed in Upvendo.
  9. Webhook state parameter: The OAuth state parameter is HMAC-signed with the webhook secret for CSRF protection. It contains the vendor_id.
  10. Token refresh: The user access token can be refreshed using the refresh token via the getUserAccessToken() method. The client access token uses client credentials flow with scopes: eats.store eats.store.orders.read eats.store.status.write eats.order.

Order Flow

Customer orders on Uber Eats
         |
Uber Eats sends webhook (orders.notification) to Upvendo
         |
ProcessUberEatsOrderNotificationJob (queued)
         |
Full order fetched from Uber Eats API
         |
Order auto-accepted via API
         |
ThirdPartyTransaction + TransactionItems created
         |
Order appears in Orders (Uber Eats channel)
         |
Kitchen prepares order
         |
Mark as Ready -> Uber Eats notifies driver
         |
Driver picks up -> Order complete

Note: Payment is handled by Uber Eats. You receive payouts from Uber Eats directly.


Syncing Menu

  • Changes in Upvendo can be pushed to Uber Eats via Uber Eats -> Sync Menu
  • Review changes before publishing
  • The sync is a full menu replacement

Item Availability

  • Mark items unavailable temporarily
  • Set schedule-based availability
  • Sync stock levels (optional)

FAQs

Why do I get redirected to Uber Eats when enabling the integration?

The first time any location for a vendor enables Uber Eats, you must complete OAuth authorization. This grants Upvendo permission to manage your stores. After the first authorization, additional locations can be linked without OAuth.

How do I know which Store ID to select?

After OAuth, the store list is automatically fetched from your Uber Eats account. The dropdown shows store names and IDs. Match the store to the Upvendo location by name/address.

Can I sync multiple menus at once?

Yes. The Sync Menu action accepts an array of menu IDs. All selected menus are combined into a single payload.

Are orders automatically accepted?

Yes. The POS provisioning sets require_manual_acceptance: false, and the order notification job calls the Uber Eats accept endpoint automatically. Orders appear in Upvendo already accepted.

Can I have Uber Eats on multiple locations?

Yes. Each location has its own Uber Eats store linking. The OAuth tokens are shared at the vendor level, so you only authorize once.

What happens if I disable the integration?

Disabling calls Uber Eats' API to unlink the store. The integration record is deleted. You will stop receiving orders for that location.

Why can't I update the integration settings?

The update endpoint is not currently supported. To change settings (like store ID or sandbox mode), disable the integration and re-enable with new settings.

What is the difference between the two types of access tokens?

  • User access token (authorization code flow): Used for POS provisioning and store list retrieval. Requires user login.
  • Client access token (client credentials flow): Used for menu sync, order fetching, and order acceptance. Does not require user interaction.

Troubleshooting

Orders not coming through

  • Check connection status in Integrations
  • Verify restaurant is online in Uber Eats Manager
  • Check Activity Log for errors
  • Ensure the webhook endpoint POST /webhook/uber-eats is reachable
  • Verify the verify.uber-eats-webhook middleware is not rejecting requests
  • Check that order_release_webhooks is enabled (set during provisioning)
  • The store ID may be invalid or already linked to another POS system
  • The user access token may have expired. Try disabling and re-enabling (which will trigger OAuth again)
  • Check the Uber Eats Manager for any account restrictions

OAuth redirect fails or loops

  • Ensure UBER_EATS_REDIRECT_URI is correctly configured and matches the Uber Eats app settings
  • The state parameter must be valid. If HMAC verification fails, the callback will be rejected.
  • Check that the vendor ID in the state matches the current user's vendor
  • Verify the store ID is correct and the store is active
  • Check that menu items have valid data (names, prices, tax rates)
  • Ensure the client access token is valid (the system uses client credentials flow)
  • Look for specific errors in the Activity Log
  • Uber Eats may reject menus with invalid modifier quantity constraints
  • Verify item mapping is complete
  • Check for price/description mismatches
  • Contact Uber Eats support for catalog issues

Driver issues

  • Contact Uber Eats support directly
  • Note order ID from order details

"Uber Eats integration already enabled for this location"

  • Each location can only have one active Uber Eats integration
  • Disable the existing integration before enabling a new one

Orders showing wrong item prices

  • The order notification job uses Uber Eats-specific pricing (getPrice('uber_eats')) from Upvendo items
  • Make sure you have set the Uber Eats price on your items if it differs from the default price
  • Re-sync the menu after updating prices

Assistant Guidance

When helping users with Uber Eats integration:

  • Check if the vendor has completed OAuth first -- if not, they need to authorize before selecting a store
  • Remind users that menu sync is manual -- changes in Upvendo do not auto-push to Uber Eats
  • If orders are not coming through, verify webhook configuration and store provisioning
  • For "update not supported" errors, guide users to disable and re-enable
  • Uber Eats payments are fully external -- do not suggest configuring payment profiles