> ## Documentation Index
> Fetch the complete documentation index at: https://docs.everybite.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get up and running with the SmartMenu API

<Warning>
  **Sandbox Coming Soon** — We're rolling out developer sandbox access. [Contact us](mailto:api-partnerships@everybite.com) to join the early access waitlist.
</Warning>

This guide walks you through integrating the SmartMenu API into your ordering platform—from initial setup to personalized menu experiences.

## Onboarding Checklist

<Steps>
  <Step title="Get API Credentials">
    [Contact your EveryBite partnership manager](mailto:api-partnerships@everybite.com) to receive your staging and production API keys.
  </Step>

  <Step title="Configure Your Chain">
    Work with EveryBite to set up your restaurant chain, locations, and menu sync.
  </Step>

  <Step title="Integrate the API">
    Follow the steps below to make your first API calls.
  </Step>

  <Step title="Test in Staging">
    Validate your integration against the staging environment with test data.
  </Step>

  <Step title="Go Live">
    Switch to production credentials and launch personalized menus to your guests.
  </Step>
</Steps>

### Timeline

| Phase           | Duration  | Activities                         |
| --------------- | --------- | ---------------------------------- |
| **Setup**       | 1-2 days  | Credentials, chain configuration   |
| **Development** | 1-2 weeks | API integration, UI implementation |
| **Testing**     | 3-5 days  | QA, edge cases, performance        |
| **Launch**      | 1 day     | Production deployment              |

***

## What You'll Need

* A signed partnership agreement with EveryBite
* API credentials for your authorized brand
* Access to your ordering solution (currently Olo, with Toast, Square, and PAR coming soon)

## Step 1: Get Your API Credentials

Once approved, you'll receive API credentials that identify which restaurant brand's menu data your app can access.

```bash theme={null}
# Your API key will look like this:
API_KEY="pk_YWJjMTIzLWRlZjQ1Ni03ODkw.x9Kj2mNpQrStUvWxYz"
```

Use that exact `pk_...` value as the `Authorization` header. Do not prefix it with `Bearer`.

## Step 2: Start a Session

Start a session when the guest opens your app or begins browsing. Provide a stable guest identifier and we bind it to a session:

```graphql theme={null}
mutation StartGuestSession {
  startSession(
    input: {
      guestId: "guest_abc123"
      # OR passportId: "passport_abc"
      # OR email: "guest@example.com"
    }
  ) {
    sessionId
  }
}
```

<Accordion title="Example Response">
  ```json theme={null}
  {
    "data": {
      "startSession": {
        "sessionId": "sess_7f3a9c2e-8b1d-4e5f-a6c0-9d2e8f1a3b5c"
      }
    }
  }
  ```
</Accordion>

Store the returned `sessionId` — you'll include it in all subsequent requests via the `X-Session-ID` header. Guest identity is now bound to this session; chain context comes from your API key.

## Step 3: Configure Your Headers

Once you have a session, configure your HTTP client with these headers for **all API calls**:

| Header          | Required | Description                                      |
| --------------- | -------- | ------------------------------------------------ |
| `Authorization` | Yes      | Raw API key value, for example `pk_YOUR_API_KEY` |
| `Content-Type`  | Yes      | `application/json`                               |
| `X-Session-ID`  | Yes      | Session ID from Step 2                           |

That's it. Chain context comes from your API key, and guest identity and personalization context come from the session you created in Step 2.

If you are trying requests in the docs UI or directly at `https://api.everybite.com/graphql`, use `Authorization` as the header name and paste in the raw `pk_...` value.

```bash theme={null}
curl -X POST https://api.everybite.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: pk_YOUR_API_KEY" \
  -H "X-Session-ID: sess_7f3a9c2e-8b1d-4e5f-a6c0-9d2e8f1a3b5c" \
  -d '{"query": "..."}'
```

```javascript theme={null}
const headers = {
  'Content-Type': 'application/json',
  'Authorization': API_KEY,
  'X-Session-ID': sessionId
};
```

<Tip>
  **Why so simple?** You provide guest identity once when you call `startSession`. After that, every API call just needs the `X-Session-ID` header—we resolve chain, widget, and personalization context for you.
</Tip>

## Step 4: Fetch Filter Options

Before building your filter UI, fetch the available options for the restaurant:

```graphql theme={null}
query GetFilterOptions {
  filterOptions {
    diets { type displayName description isEnabled }
    allergens { type displayName icon isEnabled }
    nutrients { type displayName unit defaultMin defaultMax }
    categories { name count }
  }
}
```

<Accordion title="Example Response">
  ```json theme={null}
  {
    "data": {
      "filterOptions": {
        "diets": [
          { "type": "VEGAN", "displayName": "Vegan", "description": "No animal products", "isEnabled": true },
          { "type": "VEGETARIAN", "displayName": "Vegetarian", "description": "No meat or fish", "isEnabled": true },
          { "type": "PESCATARIAN", "displayName": "Pescatarian", "description": "Fish but no meat", "isEnabled": true }
        ],
        "allergens": [
          { "type": "DAIRY", "displayName": "Dairy", "icon": "dairy", "isEnabled": true },
          { "type": "PEANUT", "displayName": "Peanut", "icon": "peanut", "isEnabled": true },
          { "type": "TREE_NUT", "displayName": "Tree Nut", "icon": "tree-nut", "isEnabled": true }
        ],
        "nutrients": [
          { "type": "CALORIES", "displayName": "Calories", "unit": "kcal", "defaultMin": 0, "defaultMax": 2000 },
          { "type": "PROTEIN", "displayName": "Protein", "unit": "g", "defaultMin": 0, "defaultMax": 100 }
        ],
        "categories": [
          { "name": "Salads", "count": 12 },
          { "name": "Bowls", "count": 8 },
          { "name": "Wraps", "count": 6 }
        ]
      }
    }
  }
  ```
</Accordion>

## Step 5: Search Dishes with Preferences

Search for dishes that match the guest's preferences:

```graphql theme={null}
query SearchDishes($preferences: PreferencesInput) {
  search(preferences: $preferences) {
    matches {
      dish {
        id
        name
        description
        nutrition { calories protein carbohydrates }
        allergens { type displayName }
      }
      matchStatus
    }
    almostMatches {
      dish {
        id
        name
        nutrition { calories }
        allergens { type displayName }
      }
      matchStatus
      matchReasons
    }
    notMatches {
      dish { id name }
      matchStatus
      matchReasons
    }
    counts { matches almostMatches notMatches total }
  }
}
```

**Variables:**

```json theme={null}
{
  "preferences": {
    "diets": ["VEGETARIAN"],
    "excludeAllergens": ["PEANUT", "TREE_NUT"],
    "calorieRange": { "max": 600 }
  }
}
```

<Accordion title="Example Response">
  ```json theme={null}
  {
    "data": {
      "search": {
        "matches": [
          {
            "dish": {
              "id": "dish_001",
              "name": "Mediterranean Quinoa Bowl",
              "description": "Quinoa, roasted vegetables, feta, lemon tahini",
              "nutrition": { "calories": 520, "protein": 18, "carbohydrates": 62 },
              "allergens": [{ "type": "DAIRY", "displayName": "Dairy" }]
            },
            "matchStatus": "MATCH"
          }
        ],
        "almostMatches": [
          {
            "dish": {
              "id": "dish_002",
              "name": "Garden Veggie Wrap",
              "nutrition": { "calories": 480 },
              "allergens": [{ "type": "SESAME", "displayName": "Sesame" }]
            },
            "matchStatus": "ALMOST_MATCH",
            "matchReasons": ["Contains Sesame (removable)"]
          }
        ],
        "notMatches": [
          {
            "dish": { "id": "dish_003", "name": "Thai Peanut Salad" },
            "matchStatus": "NOT_MATCH",
            "matchReasons": ["Contains Peanut (excluded allergen)"]
          }
        ],
        "counts": { "matches": 1, "almostMatches": 1, "notMatches": 1, "total": 3 }
      }
    }
  }
  ```
</Accordion>

Results are grouped by match status:

| Status         | Meaning                                     | UI Recommendation      |
| -------------- | ------------------------------------------- | ---------------------- |
| `MATCH`        | Fully meets preferences                     | Show prominently       |
| `ALMOST_MATCH` | Minor conflict (e.g., removable ingredient) | Show with warning      |
| `NOT_MATCH`    | Does not meet preferences                   | Hide or show at bottom |

## Step 6: Display Results

Here's how the response data translates to a user interface:

<CardGroup cols={3}>
  <Card>
    <div style={{ marginBottom: '8px' }}>
      <span style={{ background: '#22c55e', color: 'white', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', fontWeight: 'bold' }}>MATCH</span>
    </div>

    **Mediterranean Quinoa Bowl**

    Quinoa, roasted vegetables, feta, lemon tahini

    520 cal · 18g protein · 62g carbs

    <span style={{ fontSize: '12px', color: '#64748b' }}>Contains: Dairy</span>
  </Card>

  <Card>
    <div style={{ marginBottom: '8px' }}>
      <span style={{ background: '#f59e0b', color: 'white', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', fontWeight: 'bold' }}>ALMOST MATCH</span>
    </div>

    **Garden Veggie Wrap**

    Grilled vegetables, hummus, mixed greens

    480 cal · 14g protein · 58g carbs

    <span style={{ fontSize: '12px', color: '#f59e0b' }}>⚠ Contains: Sesame (removable)</span>
  </Card>

  <Card>
    <div style={{ marginBottom: '8px' }}>
      <span style={{ background: '#ef4444', color: 'white', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', fontWeight: 'bold' }}>NOT MATCH</span>
    </div>

    **Thai Peanut Salad**

    Mixed greens, edamame, peanut dressing

    410 cal · 12g protein · 38g carbs

    <span style={{ fontSize: '12px', color: '#ef4444' }}>✕ Contains: Peanut (excluded)</span>
  </Card>
</CardGroup>

### Sample Code

```javascript theme={null}
const { matches, almostMatches, notMatches, counts } = data.search;

// Render MATCH dishes prominently
matches.forEach(({ dish, matchStatus }) => {
  renderDishCard(dish, { badge: 'green', prominent: true });
});

// Render ALMOST_MATCH with warnings
almostMatches.forEach(({ dish, matchReasons }) => {
  renderDishCard(dish, { badge: 'yellow', warnings: matchReasons });
});

// NOT_MATCH dishes: hide entirely or show at bottom
notMatches.forEach(({ dish, matchReasons }) => {
  renderDishCard(dish, { badge: 'red', muted: true, reasons: matchReasons });
});
```

***

## Get Early Access

Ready to integrate? We're onboarding partners now.

<CardGroup cols={2}>
  <Card title="Join the Waitlist" icon="envelope" href="mailto:api-partnerships@everybite.com">
    Contact us for sandbox access
  </Card>

  <Card title="Architecture" icon="sitemap" href="/docs/architecture">
    Understand how the platform works
  </Card>

  <Card title="Core Concepts" icon="book" href="/docs/concepts/hierarchy">
    Learn the data model
  </Card>

  <Card title="Authentication" icon="key" href="/docs/authentication">
    API keys and security
  </Card>
</CardGroup>
