Skip to main content
When a guest selects a dish, you can increase order value with intelligent recommendations based on what other guests with similar profiles have ordered.

Upsell vs Cross-Sell

Upsell

“Make it a large?”Upgrade within the same item—medium to large, regular to premium, add extra protein.

Cross-Sell

“Want fries with that?”Add complementary items—sides, drinks, desserts that pair well with their selection.

Classic Examples

TypeTriggerRecommendationReason
UpsellMedium DrinkLarge Drink”Only $0.50 more for 50% more”
UpsellRegular BowlProtein Bowl”92% of high-protein guests upgrade”
UpsellSingle BurgerDouble Burger”Most popular with hungry guests”
Cross-SellBurgerFries”85% of guests add fries”
Cross-SellSaladIced Tea”Popular healthy pairing”
Cross-SellEntreeDessert”Save room for our brownie?”
Segment-Driven Intelligence: Recommendations are based on co-purchase patterns within the guest’s segments. If 78% of wheat-free guests order fries with their burger, we’ll surface that pairing with high confidence.

Get Pairing Recommendations

query PairingRecommendations($input: PairingRecommendationsInput!) {
  pairingRecommendations(input: $input) {
    recommendations {
      dishId
      dishName
      description
      imageUrl
      category
      priceCents
      nutrition {
        calories
        protein
        carbohydrates
        fatTotal
      }
      allergens {
        type
        displayName
      }
      confidence
      reason
    }
    basedOnSegments
  }
}

Input

input PairingRecommendationsInput {
  dishIds: [ID!]!              # One dish (add-on) or multiple (checkout)
  categories: [String!]        # Filter: ["sides", "drinks", "desserts"]
  segments: [String!]          # Override for multi-guest orders
  excludeDishIds: [ID!]        # Items already in cart
  limit: Int                   # Default 10, max 10
}
ParameterTypeRequiredDescription
dishIds[ID!]!YesThe dish(es) to find pairings for. Single dish for add-on flow, multiple for checkout.
categories[String!]NoFilter recommendations by category (e.g., ["sides", "drinks"])
segments[String!]NoOverride guest segments. Use for multi-guest orders. If omitted, uses session context.
excludeDishIds[ID!]NoDishes already in cart—won’t be recommended
limitIntNoMax recommendations to return (default: 10, max: 10)

Response

type PairingRecommendationsResponse {
  recommendations: [PairingRecommendation!]!
  basedOnSegments: [String!]!
}

type PairingRecommendation {
  dishId: ID!
  dishName: String!
  description: String
  imageUrl: String
  category: String!
  priceCents: Int
  nutrition: Nutrition
  allergens: [Allergen!]!
  confidence: Float!
  reason: String!
}
FieldTypeDescription
recommendations[PairingRecommendation!]!Up to 10 recommended dishes, sorted by confidence
basedOnSegments[String!]!Which guest segments drove these recommendations
dishIdID!The recommended dish ID
dishNameString!Display name
descriptionStringDish description for tooltips/details
imageUrlStringImage URL for carousel display
categoryString!Category (e.g., “sides”, “drinks”, “desserts”)
priceCentsIntPrice in cents (null if unavailable)
nutritionNutritionFull nutrition panel—query just { calories } if you only need that
allergens[Allergen!]!Allergens for badge display
confidenceFloat!0.0-1.0 weighted blend across guest’s segments
reasonString!Human-readable explanation (e.g., “78% of wheat-free guests order this with burgers”)

Example: Cross-Sell (“Want fries with that?”)

Guest adds a burger to their cart. Show them complementary sides and drinks.
query GetAddOns {
  pairingRecommendations(input: {
    dishIds: ["dish_classic_burger"]
    categories: ["sides", "drinks"]
    limit: 5
  }) {
    recommendations {
      dishId
      dishName
      imageUrl
      category
      priceCents
      nutrition { calories }
      allergens { type displayName }
      confidence
      reason
    }
    basedOnSegments
  }
}

Example: Upsell (“Make it a large?”)

Guest selects a medium drink or regular bowl. Suggest the upgrade.
query GetUpsells {
  pairingRecommendations(input: {
    dishIds: ["dish_medium_drink"]
    categories: ["drinks"]
    limit: 3
  }) {
    recommendations {
      dishId
      dishName
      imageUrl
      category
      priceCents
      nutrition { calories }
      confidence
      reason
    }
    basedOnSegments
  }
}
Another common upsell — protein upgrades for bowl-based restaurants:
query GetProteinUpsell {
  pairingRecommendations(input: {
    dishIds: ["dish_regular_bowl"]
    categories: ["bowls", "proteins"]
    limit: 3
  }) {
    recommendations {
      dishId
      dishName
      priceCents
      nutrition { calories protein }
      confidence
      reason
    }
    basedOnSegments
  }
}

Example: Checkout Cross-Sell (“Complete your meal”)

Guest has multiple items in cart. Suggest complementary dishes before they complete the order.
query GetCheckoutSuggestions {
  pairingRecommendations(input: {
    dishIds: ["dish_classic_burger", "dish_fries"]
    categories: ["drinks", "desserts"]
    excludeDishIds: ["dish_classic_burger", "dish_fries"]
    limit: 4
  }) {
    recommendations {
      dishId
      dishName
      imageUrl
      category
      priceCents
      confidence
      reason
    }
    basedOnSegments
  }
}

Example: Multi-Guest Order

Override segments when ordering for multiple people with different dietary needs.
query GetPairingsForGroup {
  pairingRecommendations(input: {
    dishIds: ["dish_veggie_burger", "dish_classic_burger"]
    segments: ["vegetarian", "omnivore"]  # Override session segments
    categories: ["sides"]
    limit: 5
  }) {
    recommendations {
      dishId
      dishName
      confidence
      reason
    }
    basedOnSegments
  }
}
When you pass segments explicitly, we use those instead of the guest’s session segments. This is useful for group orders where one person is ordering for multiple guests with different preferences.

How Recommendations Work

Segment Weighting

When a guest belongs to multiple segments, we use a weighted blend:
  1. Find dishes frequently ordered with the input dish(es) by each segment
  2. Weight each segment’s contribution based on the guest’s confidence in that segment
  3. Combine into a single ranked list
For example, if a guest is 95% confident “wheat-free” and 70% confident “high-protein”:
  • Wheat-free pairings contribute more to the final score
  • High-protein pairings still influence recommendations

Confidence Threshold

We only recommend pairings where at least 50% of the segment has ordered that combination. This ensures recommendations are based on meaningful patterns, not noise.
ConfidenceMeaning
0.9+Very strong pairing—almost everyone in segment orders this
0.7-0.9Strong pairing—majority of segment orders this
0.5-0.7Moderate pairing—meets threshold, worth suggesting

Category Filtering

Use categories to control what types of items appear:
# Only sides and drinks (add-on flow)
categories: ["sides", "drinks"]

# Only desserts (end of meal)
categories: ["desserts"]

# All categories (let us decide)
# omit the parameter

UI Best Practices

Carousel Display

Most UIs display pairings in a horizontal carousel. The response includes everything you need: image, name, price, calories, allergens.

Show the Reason

The reason field explains why we’re recommending each item. Showing this builds trust: “78% of guests like you order this.”

Respect Allergens

Display allergen badges prominently. Even though we filter by segment, some pairings may contain allergens the guest should know about.

Quick Add

Make it easy to add items with one tap. The dishId and priceCents give you everything needed to add to cart.

When to Call This Endpoint

ScenarioWhen to CallInput
Add-on flowAfter guest adds a dish to cartSingle dishId, filter by relevant categories
Dish detail pageWhen viewing dish detailsSingle dishId, show “Pairs well with…”
CheckoutBefore paymentAll dishIds in cart, exclude those dishes
Order confirmationAfter order placedAll ordered dishIds, for “Next time, try…”
Don’t over-call. One call per flow is usually enough. The response is designed to give you everything you need for a carousel without additional lookups.