Developer Docs

Nutrition Platform API

Build nutrition-aware applications with food recognition, barcode scanning, and intelligent search.

Introduction

The Nutrition Platform API provides programmatic access to food recognition via AI-powered photo analysis, global barcode-based product lookup, nutrition database search, and food logging. All API responses follow a consistent JSON envelope format with built-in rate limiting metadata.

This documentation covers the REST API and the official iOS / Swift SDK. No version prefix (/v1/) is currently used — the API is accessed directly at the root.

Base URL

Environment Base URL
Production https://arsalanbackup.tailad6cf6.ts.net
Local Development http://localhost:3000
Note: There is currently no /v1/ prefix on any route. All endpoints are accessed directly at the root path.

Authentication

Most API endpoints require authentication via an API key. Keys are issued per organization and are passed in the Authorization header using the Bearer scheme.

API Key Format

Keys follow the format sk_<random_hex> and are scoped to a single organization. You can manage your API keys from the Dashboard.

httpAuthorization: Bearer sk_a1b2c3d4e5f6...7890abcdef

Example: Authenticated Request

curlcurl https://arsalanbackup.tailad6cf6.ts.net/food/search?query=chicken \
  -H "Authorization: Bearer sk_your_api_key_here"
Security: Never expose your API key in client-side code, version control, or public repositories. Store keys in environment variables or a secrets manager.

Response Format

All API responses follow a consistent JSON envelope:

✅ Success

json{
  "success": true,
  "data": { /* domain object */ },
  "meta": {
    "request_id": "uuid",
    "ratelimit_limit": 1000,
    "ratelimit_used": 42,
    "ratelimit_remaining": 958,
    "usage_warning": null
  }
}

❌ Error

json{
  "success": false,
  "error": "Human-readable message",
  "code": "ERROR_CODE",
  "details": null
}

Response Headers

Header Description
X-Request-IDUnique request identifier for tracing
X-RateLimit-LimitMonthly API call limit for the organization
X-RateLimit-UsedAPI calls used this month
X-RateLimit-RemainingCalls remaining in the current period
X-Usage-WarningPresent when usage ≥ 80%, value: approaching_limit

Error Codes & HTTP Status

HTTP Status Code Meaning
400VALIDATION_ERRORRequest body or parameters are invalid
400INVALID_JSONRequest body is not valid JSON
400INVALID_BARCODEBarcode format is invalid
400MISSING_QUERYSearch query parameter is missing
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENValid auth but insufficient permission
404NOT_FOUNDResource does not exist
413BODY_TOO_LARGERequest body exceeds 3 MB limit
429RATE_LIMITEDMonthly API call limit exceeded
500SERVER_ERRORUnexpected server error
502VISION_ERRORAI model failed or returned invalid data

Rate Limits

Rate limits are enforced on a monthly basis per organization. The limits depend on your subscription tier:

Tier Monthly Limit Price
Free100 callsFree
Starter1,000 calls$29/month
Pro10,000 calls$99/month
Enterprise100,000+ callsCustom pricing

When you exceed 80% of your monthly limit, the response includes a X-Usage-Warning: approaching_limit header. Once the limit is exceeded, subsequent requests return 429 RATE_LIMITED until the next billing cycle.


Endpoints

GET /health No Auth

Returns server health and status information. Useful for monitoring and connectivity checks.

cURL Example

curlcurl https://arsalanbackup.tailad6cf6.ts.net/health

Response

json{
  "success": true,
  "data": {
    "status": "ok",
    "version": "0.1.0",
    "uptime": 1234.5,
    "environment": "production",
    "database": "connected",
    "db_pool": {
      "active_connections": 3,
      "latency_ms": 12
    }
  },
  "meta": { "request_id": "...", /* ... */ }
}

GET /barcode/<barcode> Auth Required

Look up a product by its barcode (EAN-13 or UPC). Returns detailed nutrition information per 100g.

Path Parameters

Parameter Type Required Description
barcodestringYes8–13 digit numeric barcode (EAN-13 or UPC)

cURL Example

curlcurl https://arsalanbackup.tailad6cf6.ts.net/barcode/5901234123457 \
  -H "Authorization: Bearer sk_your_api_key"

Response

json{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "Whole Milk",
    "brand": "Organic Valley",
    "barcode": "5901234123457",
    "calories_100g": 61,
    "protein_g_100g": 3.2,
    "carbs_g_100g": 4.8,
    "fat_g_100g": 3.3,
    "fiber_g_100g": 0,
    "sugar_g_100g": 4.8,
    "sodium_mg_100g": 50,
    "serving_size": "1 cup (240ml)",
    "serving_g": 240,
    "image_url": "https://...",
    "source": "open_food_facts"
  },
  "meta": { /* rate limit info */ }
}

POST /log Auth Required

Create a food log entry for a user. If the user_external_id does not exist in your organization, it will be auto-created.

Request Body

Field Type Required Description
user_external_idstringYesYour own unique user identifier
food_namestringYesName of the food
sourcestringYesphoto, barcode, search, or manual
serving_qtynumberYesNumber of servings (e.g. 1.5)
meal_typestringYesbreakfast, lunch, dinner, or snack
caloriesnumberNoTotal calories for the entry
protein_gnumberNoTotal protein in grams
carbs_gnumberNoTotal carbohydrates in grams
fat_gnumberNoTotal fat in grams
serving_unitstringNoUnit (default: "serving")
brandstringNoBrand name (optional)
barcodestringNoAssociated barcode
logged_atstringNoISO 8601 timestamp (default: now)

cURL Example

curlcurl https://arsalanbackup.tailad6cf6.ts.net/log \
  -H "Authorization: Bearer sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
  "user_external_id": "user_abc123",
  "food_name": "Grilled Chicken Salad",
  "source": "manual",
  "serving_qty": 1,
  "meal_type": "lunch",
  "calories": 420,
  "protein_g": 35,
  "carbs_g": 12,
  "fat_g": 24
}'

Response

json{
  "success": true,
  "data": {
    "id": "log_entry_uuid",
    "user_id": "internal_user_uuid",
    "org_id": "org_uuid",
    "food_name": "Grilled Chicken Salad",
    "meal_type": "lunch",
    "source": "manual",
    "serving_qty": 1,
    "serving_unit": "serving",
    "calories": 420,
    "protein_g": 35,
    "carbs_g": 12,
    "fat_g": 24,
    "logged_at": "2026-05-07T22:00:00Z",
    "created_at": "2026-05-07T22:00:00Z"
  },
  "meta": { /* rate limit info */ }
}

GET /log/<user_external_id> Auth Required

Retrieve all food log entries for a given user. Only returns entries that have not been deleted (soft delete).

Query Parameters

Parameter Type Required Description
datestringNoFilter by date in YYYY-MM-DD format

cURL Example

curlcurl "https://arsalanbackup.tailad6cf6.ts.net/log/user_abc123?date=2026-05-07" \
  -H "Authorization: Bearer sk_your_api_key"

Response

json{
  "success": true,
  "data": [
    {
      "id": "log_entry_uuid",
      "food_name": "Grilled Chicken Salad",
      "meal_type": "lunch",
      "calories": 420,
      "logged_at": "2026-05-07T22:00:00Z"
      // ... full FoodLogEntry object
    }
  ],
  "meta": { /* rate limit info */ }
}

DELETE /log/<id> Auth Required

Delete a food log entry. This is a soft delete — the entry is hidden from GET /log but retained in the database for recovery and auditing.

cURL Example

curlcurl -X DELETE https://arsalanbackup.tailad6cf6.ts.net/log/log_entry_uuid \
  -H "Authorization: Bearer sk_your_api_key"

Response

json{
  "success": true,
  "data": {
    "deleted": true
  },
  "meta": { /* rate limit info */ }
}

POST /analyze/photo Auth Required

Analyze a food photo using a vision AI model. The model identifies foods, estimates portion sizes, and calculates nutritional breakdown.

Image limits: The image_base64 string must be a valid JPEG image encoded as base64. PNG and other formats are not accepted. The decoded image size must not exceed 3 MB.

Request Body

Field Type Required Description
image_base64stringYesBase64-encoded JPEG image only (max 3 MB decoded)
meal_typestringNobreakfast, lunch, dinner, or snack

cURL Example

curlcurl https://arsalanbackup.tailad6cf6.ts.net/analyze/photo \
  -H "Authorization: Bearer sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
  "image_base64": "/9j/4AAQSkZJRg...base64_encoded_image_data...",
  "meal_type": "dinner"
}'

Response

json{
  "success": true,
  "data": {
    "foods": [
      {
        "name": "Grilled Chicken Breast",
        "estimated_portion": "150g",
        "calories": 248,
        "protein_g": 46.5,
        "carbs_g": 0,
        "fat_g": 5.2,
        "fiber_g": 0,
        "confidence": "high"
      },
      {
        "name": "Roasted Vegetables",
        "estimated_portion": "100g",
        "calories": 85,
        "protein_g": 2.1,
        "carbs_g": 15,
        "fat_g": 2.5,
        "fiber_g": 4,
        "confidence": "medium"
      }
    ],
    "meal_description": "A grilled chicken breast with roasted vegetables"
  },
  "meta": {
    "cost": 0.005,
    "tokens": 450,
    "latency_ms": 2340,
    "request_id": "req_abc123",
    "ratelimit_remaining": 957
  }
}

GET /usage Auth Required

Retrieve current usage statistics for your organization, including call counts, cost estimates, and daily breakdown.

cURL Example

curlcurl https://arsalanbackup.tailad6cf6.ts.net/usage \
  -H "Authorization: Bearer sk_your_api_key"

Response

json{
  "success": true,
  "data": {
    "org_id": "uuid",
    "tier": "starter",
    "monthly_limit": 1000,
    "used_this_month": 342,
    "remaining": 658,
    "estimated_cost_usd": 12.45,
    "daily_breakdown": [
      {
        "date": "2026-05-07",
        "photo_analyses": 10,
        "barcode_scans": 5,
        "text_searches": 2,
        "total": 17
      }
    ]
  },
  "meta": { /* rate limit info */ }
}

iOS / Swift SDK

The official iOS SDK provides a native Swift interface to the Nutrition Platform API. It is distributed via Swift Package Manager (SPM).

Installation

Add the package to your Package.swift or Xcode project:

Via Xcode

  1. File → Add Package Dependencies...
  2. Enter: https://github.com/iArsalanshah/nutrition-platform
  3. Select "Up to Next Major" version and add the NutritionPlatform library to your target

Via Package.swift

swiftdependencies: [
  .package(
    url: "https://github.com/iArsalanshah/nutrition-platform",
    from: "0.1.0"
  )
]

Initialization

swiftimport NutritionPlatform

// Initialize with your API key
let client = NutritionClient(
  apiKey: "sk_your_api_key_here",
  baseUrl: "https://arsalanbackup.tailad6cf6.ts.net"
)
The default baseUrl points to a staging/v1 URL but you should set it to the production URL shown above during setup.

Client Methods

analyzePhoto

Analyze a food photo using a vision AI model.

swiftlet result = try await client.analyzePhoto(
  imageBase64: base64String,
  mealType: "dinner"
)

// Access detected foods
for food in result.data.foods {
  print(food.name)          // e.g. "Grilled Chicken Breast"
  print(food.calories)      // 248.0
  print(food.confidence)    // "high"
}

// Meal description
print(result.data.mealDescription)

// Response metadata (rate limits, model info, etc.)
print(result.meta.requestId)

lookupBarcode

Look up a product by barcode.

swiftlet product = try await client.lookupBarcode("5901234123457")

print(product.data.name)           // "Whole Milk"
print(product.data.calories100g)   // 61.0
print(product.data.brand)          // "Organic Valley"

searchFood

Search the nutrition database for food items.

swiftlet searchResults = try await client.searchFood(
  query: "chicken breast",
  source: "all",
  page: 1,
  limit: 20
)

print(searchResults.data.total)       // Total results count
print(searchResults.data.hasMore)    // true if more pages

for item in searchResults.data.results {
  print(item.name)
  print(item.calories100g)
}

createLogEntry

Create a food log entry.

swiftlet entry = CreateLogEntryRequest(
  userExternalId: "user_abc123",
  foodName: "Grilled Chicken Salad",
  mealType: "lunch",
  source: "manual",
  servingQty: 1,
  servingUnit: "bowl",
  calories: 420,
  proteinG: 35,
  carbsG: 12,
  fatG: 24
)

let logEntry = try await client.createLogEntry(entry)
print(logEntry.data.id)        // The created entry's ID
print(logEntry.data.loggedAt)  // ISO 8601 timestamp

getLogs

Retrieve food log entries for a user.

swift// Get all logs for a user
let logs = try await client.getLogs(forUser: "user_abc123")

// Filter by date
let todaysLogs = try await client.getLogs(
  forUser: "user_abc123",
  date: "2026-05-07"
)

for entry in logs.data {
  print(entry.foodName)
  print(entry.calories)
}

deleteLogEntry

Delete a food log entry (soft delete).

swifttry await client.deleteLogEntry(id: "log_entry_uuid")
// Entry is soft-deleted — hidden from getLogs but retained for auditing

Error Handling

All SDK methods throw NutritionError on failure. Use try/catch to handle errors:

swiftdo {
  let result = try await client.analyzePhoto(imageBase64: image)
  // Handle success
} catch let error as NutritionError {
  switch error {
  case .httpError(let status, let message, let code):
    print("HTTP \(status): \(message) [\(code ?? "N/A")]")
  case .decodingError(let underlying):
    print("Failed to parse response: \(underlying)")
  case .networkError(let underlying):
    print("Network error: \(underlying)")
  case .invalidURL:
    print("Invalid URL configured")
  case .maxRetriesExceeded:
    print("Request failed after retries")
  }
} catch {
  print("Unexpected error: \(error)")
}

Response Metadata

Every SDK method returns a NutritionResponse<T> wrapper with a meta property containing rate limit information:

swiftlet result = try await client.searchFood(query: "apple")

// Rate limit info from response headers
print(result.meta.requestId)              // UUID for tracing
print(result.meta.rateLimitRemaining)     // Calls remaining
print(result.meta.usageWarning)           // "approaching_limit" or nil
print(result.meta.retryAfter)             // Seconds to wait (on 429)

Model Types

The SDK defines the following key models (all Codable and Sendable):

Type Description
PhotoAnalysisResultContains foods: [RecognizedFood] and mealDescription: String
RecognizedFoodA food item identified in a photo with nutrition estimates
BarcodeProductProduct details from a barcode lookup
FoodSearchResultA single search result item
SearchResultPaginated search results with results, total, page, limit, hasMore
CreateLogEntryRequestRequest body for creating a log entry
FoodLogEntryA food log entry with full nutrition breakdown
NutritionResponse<T>Generic response wrapper with data and meta
ResponseMetaRate limit metadata from response headers
NutritionErrorError enum with httpError, decodingError, networkError, etc.

Full Example

swiftimport NutritionPlatform

let client = NutritionClient(
  apiKey: "sk_your_api_key",
  baseUrl: "https://arsalanbackup.tailad6cf6.ts.net"
)

do {
  // 1. Search for a food
  let search = try await client.searchFood(query: "oatmeal", limit: 5)
  print("Found \(search.data.total) results")

  // 2. Create a log entry
  let entry = CreateLogEntryRequest(
    userExternalId: "user_abc",
    foodName: "Oatmeal with Berries",
    mealType: "breakfast",
    source: "search",
    servingQty: 1,
    calories: 320,
    proteinG: 12,
    carbsG: 54,
    fatG: 5
  )
  let created = try await client.createLogEntry(entry)
  print("Created log entry: \(created.data.id)")

  // 3. List today's logs
  let logs = try await client.getLogs(forUser: "user_abc", date: "2026-05-07")
  print("Today's entries: \(logs.data.count)")

  // 4. Check usage
  // (no SDK method for /usage — use direct API call if needed)
} catch {
  print("Error: \(error)")
}
Rate limit metadata is available on every NutritionResponse via the meta property — check result.meta.rateLimitRemaining to monitor your usage from within your app.

Contact & Support

Have questions, need help integrating, or want to report an issue? Our team is here to help.

Email Support

Send us a message at support@nutritionplatform.com and we'll get back to you within 24 hours.


Nutrition Platform API — v0.1.0

↑ Back to Top