v1 · In development

Bitefull API

A REST API for recipes, meal planning, shopping lists, and pantry management.

Discover and author recipes, generate weekly meal plans around dietary goals, turn plans into de-duplicated shopping lists, and track pantry inventory. JSON over HTTPS.

Endpoints are live on the development server and may change before the stable v1 release.

Base URL & versioning

Every endpoint lives under a versioned prefix:

https://api.kyox.io/bitefull/v1

The version is part of the path. Breaking changes ship under a new version (/v2) while older versions keep working. The interactive reference is at /bitefull/v1/docs.

Authentication

Bitefull uses two layers. An API key identifies the calling app or account and is required on every request. A user token (JWT) identifies an end-user and is required only on user-scoped routes.

API key

Send your key in the X-API-Key header on every request. Keys gate access to the API and are how usage is metered per account.

X-API-Key: bk_live_<your-key>

Manage keys at /api-keys (create, list, revoke). A key's secret is shown once at creation — store it securely; it can't be retrieved again. Requests without a valid key return 401.

User token

Register or log in to receive a short-lived access token and a rotating refresh token. Send the access token alongside your API key on authenticated routes:

X-API-Key: bk_live_<your-key>
Authorization: Bearer <accessToken>

Access tokens expire after 15 minutes. Exchange a refresh token at POST /auth/refresh for a new pair. Refresh tokens rotate on every use — reusing an old one revokes the whole session family.

Quick start

# Register a user (API key required on every call)
curl -X POST https://api.kyox.io/bitefull/v1/auth/register \
  -H "X-API-Key: bk_live_<your-key>" \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","username":"chef","password":"Secret123"}'

# Call a user-scoped route with both credentials
curl https://api.kyox.io/bitefull/v1/auth/me \
  -H "X-API-Key: bk_live_<your-key>" \
  -H "Authorization: Bearer <accessToken>"

Roles: USER, PREMIUM, ADMIN — used for authorization and rate-limit tiers.

Errors

Errors use standard HTTP status codes and a consistent JSON envelope:

{
  "statusCode": 401,
  "error": "UnauthorizedException",
  "message": "Invalid credentials",
  "path": "/bitefull/v1/auth/login",
  "timestamp": "2026-06-01T12:00:00.000Z"
}
CodeMeaning
400Bad request
401Missing or invalid token
403Authenticated but not allowed
404Resource not found
409Conflict (e.g. email taken)
422Validation failed (message is a list)
429Rate limit exceeded

Rate limits

Limits scale with your tier, counted per rolling 60-second window:

TierRequests / minute
Anonymous60
USER300
PREMIUM / ADMIN1200

Exceeding the limit returns 429 Too Many Requests.

API Keys

Issue and manage the keys that gate API access. These routes require a user token; the very first key is minted server-side.

POST/api-keysCreate a key (secret shown once) auth
GET/api-keysList your keys auth
DELETE/api-keys/:idRevoke a key auth

Create a key

POST /api-keys
{ "name": "Acme production", "expiresInDays": 365 }

The response includes key exactly once — store it now. Optionally set rateLimitPerMin to override the tier limit for a paid plan.

Auth

POST/auth/registerCreate account, return tokens
POST/auth/loginAuthenticate, return tokens
POST/auth/refreshRotate refresh → new tokens
POST/auth/logoutRevoke a refresh token auth
GET/auth/meCurrent user auth

Example response

{
  "accessToken": "eyJhbGciOi...",
  "refreshToken": "k3jf9...",
  "tokenType": "Bearer",
  "expiresIn": 900
}

Recipes

GET/recipesList published (paginated)
GET/recipes/searchFull-text + filters
GET/recipes/categoriesBrowse facets + counts
GET/recipes/trendingPopular recipes
GET/recipes/recommendedPersonalized auth
GET/recipes/:idSingle recipe
POST/recipesCreate auth
PUT/recipes/:idUpdate (author/admin) auth
DELETE/recipes/:idDelete (author/admin) auth

Search

Combine free-text with structured filters. All parameters are optional:

ParamExampleNotes
qsalmonFull-text over title, cuisine, tags, description
dietVEGANRepeatable; recipe must match all
tagsbreakfastRepeatable; recipe must carry all (meal types, descriptors)
cuisineMediterranean
maxTime30Total minutes
minCalories / maxCalories300 / 700Per serving
difficultyEASYEASY · MEDIUM · HARD
sortratingrelevance · rating · popular · newest · quickest
page / limit1 / 20Pagination
curl "https://api.kyox.io/bitefull/v1/recipes/search?q=salmon&diet=PESCATARIAN&maxTime=40"

Filtering lives on /recipes/search. The plain GET /recipes list only paginates — it ignores cuisine, diet, tags and the other filters.

Browse & categories

GET /recipes/categories returns the facets for building browse menus and home sections. Each entry is { value, count } (meal types also include a label), plus a filterParam map naming the /recipes/search parameter that applies each facet:

FacetApply on /recipes/search via
cuisines?cuisine=
mealTypes?tags=
diets?diet=
difficulties?difficulty=
popularTags?tags=
curl "https://api.kyox.io/bitefull/v1/recipes/categories"
curl "https://api.kyox.io/bitefull/v1/recipes/search?cuisine=Thai&tags=dinner&sort=rating"

Create a recipe

POST /recipes
{
  "title": "Grilled Chicken Bowl",
  "servings": 2,
  "prepTime": 10, "cookTime": 20,
  "difficulty": "EASY",
  "cuisine": "American",
  "diets": ["DAIRY_FREE"],
  "tags": ["high-protein"],
  "ingredients": [
    { "name": "chicken breast", "quantity": 300, "unit": "GRAM" },
    { "name": "white rice", "quantity": 200, "unit": "GRAM" }
  ],
  "instructions": [
    { "step": 1, "text": "Cook the rice." },
    { "step": 2, "text": "Grill the chicken." }
  ],
  "publish": true
}

Per-serving nutrition (calories, protein, carbs, fat, fiber, sodium) is computed automatically from ingredient data.

Engagement

POST/recipes/:id/saveSave a recipe auth
GET/recipes/savedYour saved recipes auth
POST/recipes/:id/cookLog a cook auth
POST/recipes/:id/rateRate 1–5 auth

Meal plans

GET/meal-plansYour plans auth
POST/meal-plansCreate manually auth
POST/meal-plans/generateAuto-generate auth
GET/meal-plans/:idSingle plan auth
PUT/meal-plans/:idReplace entries auth
DELETE/meal-plans/:idDelete auth

Generate a plan

The generator fills each day and slot with recipes that satisfy dietary restrictions, hit a daily calorie band, prefer your cuisines and pantry-covered recipes, and avoid repeats. Unspecified options fall back to your saved preferences.

POST /meal-plans/generate
{
  "startDate": "2026-06-08",
  "days": 7,
  "slots": ["BREAKFAST", "LUNCH", "DINNER"],
  "diets": ["VEGAN"],
  "dailyCalorieGoal": 1800,
  "cuisines": ["Mediterranean"],
  "usePantry": true
}

Shopping lists

GET/shopping-listsYour lists auth
POST/shopping-listsCreate empty auth
POST/shopping-lists/generateFrom recipes/plan auth
PATCH/shopping-lists/items/:idTick off / adjust auth

Generate from a meal plan

Collects every ingredient across the chosen recipes (or a whole meal plan), normalizes units, aggregates duplicates, and subtracts what your pantry already covers.

POST /shopping-lists/generate
{ "mealPlanId": "8bc883fc-...", "subtractPantry": true }

Pantry

GET/pantryList items auth
POST/pantryAdd item auth
PATCH/pantry/:idUpdate item auth
DELETE/pantry/:idRemove item auth
POST /pantry
{ "ingredientName": "olive oil", "quantity": 500, "unit": "GRAM", "expirationDate": "2026-12-01" }

Users

GET/users/meProfile + preferences auth
PATCH/users/meUpdate profile/preferences auth
DELETE/users/meDeactivate account auth

Dietary preferences set here (diets, allergens, preferred cuisines, daily calorie goal) become the defaults for search, recommendations, and meal-plan generation.