Skip to main content
This guide walks partners through integrating the SmartMenu API into their ordering platform.

Prerequisites

Before starting integration:
  1. API Key: Obtain from EveryBite partnership team
  2. Chain Setup: Your restaurant chain(s) configured in EveryBite
  3. Data Sync: Menu data synced between your ordering system and EveryBite
  4. Nutrition Data: Restaurant has provided nutrition/allergen data

Integration Checklist

Phase 1: Setup

  • Receive API key and staging environment access
  • Confirm chain ID(s) for your restaurants
  • Verify menu data sync is complete
  • Test authentication with filterOptions query

Phase 2: Session Tracking

  • Implement startSession mutation when user begins ordering
  • Pass chain, platform, guest identity, and passport (if applicable) to startSession
  • Store returned sessionId and include in X-Session-ID header on all subsequent calls

Phase 3: Core Functionality

  • Implement search with search query
  • Display match groups (matches, almost matches, not matches)
  • Implement dish details with dish query
  • Display nutrition panel and allergen badges

Phase 4: Enhanced Features

  • Implement BYO customization (if applicable)
  • Real-time nutrition calculation
  • Ingredient-level allergen warnings

Phase 5: Go Live

  • Switch to production API key
  • Verify analytics events flowing to EveryBite
  • Monitor error rates and latency
  • Update privacy policy

Implementation Patterns

Pattern 1: Filter-First Experience

Best for apps where personalization is the primary feature. Example Implementation:
// 1. Start session when app loads (all context bound here)
useEffect(() => {
  const guestId = getGuestIdFromStorage() || generateGuestId();
  const passportId = getPassportIdFromStorage(); // null if guest

  const { data } = await graphqlClient.mutate({
    mutation: START_SESSION,
    variables: {
      input: {
        chainId: 'honeygrow',
        restaurantId: 'loc_philly_walnut',
        guestId,
        passportId,
        platform: 'IOS',
        appVersion: '3.2.1'
      }
    }
  });

  // Store session ID for all subsequent calls
  setSessionId(data.startSession.sessionId);
}, []);

// 2. Search with preferences (context comes from session)
async function searchDishes(preferences) {
  const { data } = await graphqlClient.query({
    query: SMART_MENU_SEARCH,
    variables: {
      preferences: {
        diets: preferences.diets,
        excludeAllergens: preferences.allergens,
        calorieRange: preferences.calorieRange
      }
    },
    context: {
      headers: {
        'X-Session-ID': sessionId
      }
    }
  });

  return data.search;
}

Pattern 2: Overlay Enhancement

Best for apps with existing menu browsing where personalization is secondary.

Pattern 3: Real-Time BYO

For customizable dishes with live nutrition updates.
// 1. Load customization options
async function loadCustomizationOptions(dishId) {
  const { data } = await graphqlClient.query({
    query: DISH_CUSTOMIZATION_OPTIONS,
    variables: { dishId }
  });
  return data.dishCustomization;
}

// 2. Calculate nutrition when user changes selections
async function calculateNutrition(dishId, selections) {
  const { data } = await graphqlClient.mutate({
    mutation: CALCULATE_CUSTOM_NUTRITION,
    variables: {
      dishId,
      selections
    }
  });

  // Update UI with calculated nutrition
  // Show allergen warnings
  return data.calculateCustomNutrition;
}

GraphQL Client Setup

Apollo Client (React)

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

const httpLink = createHttpLink({
  uri: 'https://api.everybite-stage.com/smartmenu/graphql',
});

const authLink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      'Authorization': process.env.SMARTMENU_API_KEY,
      'X-Session-ID': getSessionId(),
    }
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

Fetch (Vanilla JS)

async function smartMenuQuery(query, variables) {
  const response = await fetch('https://api.everybite-stage.com/smartmenu/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': API_KEY,
      'X-Session-ID': sessionId,
    },
    body: JSON.stringify({ query, variables })
  });

  const { data, errors } = await response.json();

  if (errors) {
    throw new Error(errors[0].message);
  }

  return data;
}

Python (requests)

import requests

class SmartMenuClient:
    def __init__(self, api_key, session_id):
        self.endpoint = 'https://api.everybite-stage.com/smartmenu/graphql'
        self.headers = {
            'Content-Type': 'application/json',
            'Authorization': api_key,
            'X-Session-ID': session_id,
        }

    def query(self, query, variables=None):
        response = requests.post(
            self.endpoint,
            headers=self.headers,
            json={'query': query, 'variables': variables or {}}
        )
        result = response.json()

        if 'errors' in result:
            raise Exception(result['errors'][0]['message'])

        return result['data']

Testing

Staging Environment

Use staging environment for development and testing:
Endpoint: https://api.everybite-stage.com/smartmenu/graphql

Test Scenarios

ScenarioExpected Result
Search with no preferencesReturns all dishes ungrouped
Search with VegetarianMeat dishes in “Not Matches”
Search with allergen exclusionDishes with allergen in “Not Matches”
View dish with allergensAllergen badges displayed
BYO with allergen ingredientWarning displayed
Invalid session ID400 error with clear message
Missing required header400 error specifying which header

Sample Test Queries

Remember to include the X-Session-ID header with a valid session ID on all requests. See the Session endpoint for details on starting a session.
# Test 1: Basic connectivity
query { __typename }

# Test 2: Filter options (context from X-Session-ID header)
query { filterOptions { diets { type } } }

# Test 3: Search (context from X-Session-ID header)
query {
  search {
    counts { total }
  }
}

# Test 4: Dish details (context from X-Session-ID header)
query { dish(id: "test-dish-id") { name, nutrition { calories } } }

Go-Live Checklist

  • Switch to production API key and endpoint
  • Update base URL to https://api.everybite.com/smartmenu/graphql
  • Verify all required headers are sent on every request
  • Test error handling in production
  • Monitor latency and error rates
  • Confirm analytics events visible in EveryBite dashboard
  • Update privacy policy to disclose data sharing with EveryBite

Support