TasteRay Emotional API - LLM Documentation

Emotional AI-Powered Personalization Platform Version: 2.0.0 Last Updated: 2025-12-04 Base URL: https://api.tasteray.com


Table of Contents

  1. Overview
  2. Authentication
  3. Rate Limiting
  4. API Endpoints
  5. Data Models
  6. Supported Verticals
  7. Building "For You" Experiences
  8. Error Handling
  9. Code Examples
  10. Best Practices

Overview

TasteRay Emotional API is an Emotional AI-powered personalization platform. It understands not just WHAT users want, but WHY they want it - creating recommendations that truly connect. Perfect for building "For You" feeds, personalized tabs, and smart carousels.

Key Features

  • Emotional AI: Understands the underlying needs driving user preferences
  • "For You" Ready: Designed for building personalized feeds, tabs, and surfaces
  • Multi-vertical Support: Works across any domain - entertainment, travel, products, services
  • Stateless Architecture: All context is provided in each request; no server-side sessions
  • Detailed Explanations: Every recommendation explains WHY it's a great match
  • Structured JSON Output: Type-safe responses with Zod schema validation
  • Edge-Deployed: Global low latency via Cloudflare Workers (<2s p95)
  • Rate Limiting: Tier-based limits to ensure fair usage

Technology Stack

  • Runtime: Cloudflare Workers (V8 isolates on edge)
  • Framework: Hono v4.0+ (lightweight web framework)
  • AI Model: Frontier LLMs with automatic fallback
  • Prompt Management: Langfuse (for versioning and tracing)
  • Storage: Cloudflare KV (for API keys, rate limits, usage stats)
  • Validation: Zod schemas for type-safe requests

Authentication

All API requests (except /v1/health) require authentication using an API key in the request header.

Header Format

X-API-Key: reco_live_your_api_key_here

API Key Formats

  • Test keys: reco_test_* - For development and testing
  • Live keys: reco_live_* - For production use

Security

  • API keys are hashed using SHA-256 before storage
  • Keys are never logged or exposed in responses
  • Revoked keys return 401 Unauthorized

Obtaining an API Key

  1. Sign up at https://api.tasteray.com/generate-key
  2. Navigate to Dashboard > API Keys
  3. Click "Create New Key"
  4. Copy and securely store your key (shown only once)

Rate Limiting

Rate limits are enforced per API key using a sliding window algorithm (1-minute windows).

Rate Limit Tiers

Tier Requests/Month Requests/Minute Typical Use Case
Free 1,000 5 Testing, demos
Basic 10,000 50 Small apps
Pro 100,000 200 Production apps
Enterprise Unlimited Custom High-scale apps

Rate Limit Headers

Every response includes rate limit information:

X-RateLimit-Limit: 50
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1699123456
X-RateLimit-Tier: pro

Handling Rate Limits

When you exceed your rate limit:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded for your tier",
    "retry_after": 60
  }
}

Response Status: 429 Too Many Requests

Best Practice: Implement exponential backoff:

Wait time = min(base_delay * (2 ^ attempt), max_delay)

API Endpoints

1. POST /v1/recommend

Generate personalized recommendations for any vertical.

Endpoint: POST https://api.tasteray.com/v1/recommend

Request Headers

Content-Type: application/json
X-API-Key: reco_live_your_api_key_here

Request Body Schema

{
  "vertical": "string (required)",
  "context": {
    "preferences": ["string (conditional, required if profile not provided)"],
    "profile": "string (conditional, free-form user profile text)",
    "constraints": {
      "key": "value (optional)"
    },
    "history": [
      {
        "item": "string (required)",
        "rating": "string (required)",
        "metadata": {}
      }
    ],
    "history_text": "string (optional, free-form history text)"
  },
  "items": [
    {
      "id": "string (required)",
      "name": "string (required)",
      "description": "string (optional)",
      "metadata": {}
    }
  ],
  "options": {
    "count": "number (1-10, default: 3)",
    "include_alternatives": "boolean (default: true)",
    "explanation_depth": "string (brief|detailed, default: detailed)",
    "language": "string (locale code, default: en_US)",
    "grounding": "boolean (enable web search, default: true when no items, false with items)",
    "fast": "boolean (enable fast inference, default: false)"
  }
}

Request Parameters

Field Type Required Description
vertical string Yes Vertical type (e.g., movies, restaurants, products, travel)
context.preferences string[] Conditional User preferences (min 1, max 20). Required if profile not provided
context.profile string Conditional Free-form text describing user profile/preferences. Required if preferences not provided
context.constraints object No Vertical-specific constraints (budget, location, etc.)
context.history array No Previous items with ratings (max 50 items)
context.history[].item string Yes Name/identifier of item
context.history[].rating string Yes User's rating (flexible format)
context.history[].metadata object No Additional context
context.history_text string No Free-form text describing user history (alternative to structured history)
items array No Specific items to choose from
items[].id string Yes Unique identifier
items[].name string Yes Item name
items[].description string No Item description
items[].metadata object No Additional metadata
options.count number No Number of recommendations (1-10, default: 3)
options.include_alternatives boolean No Include alternatives (default: true)
options.explanation_depth string No brief or detailed (default: detailed)
options.language string No Locale code for response language (e.g., en_US, es_ES, fr_FR, default: en_US)
options.grounding boolean No Enable web search for real-time information (default: true when no items provided, false when items are provided)
options.fast boolean No Enable fast inference for faster responses (default: false)

Response

Status: 200 OK

{
  "recommendations": [
    {
      "item": {
        "name": "The Matrix",
        "vertical": "entertainment",
        "type": "movie",
        "metadata": {
          "year": 1999,
          "runtime": 136,
          "genre": ["Sci-Fi", "Action"],
          "director": "Lana Wachowski, Lilly Wachowski",
          "rating": 8.7
        }
      },
      "explanation": {
        "why_match": "The film that redefined sci-fi. Still unmatched.",
        "key_factors": [
          "Questions that linger. What is real? What is control?",
          "Action that changed cinema. Groundbreaking choreography.",
          "136 minutes that fly by. Every scene earns its place."
        ],
        "potential_concerns": [
          "Intense action sequences. Not for the faint of heart.",
          "Demands your attention. The philosophy rewards focus."
        ]
      },
      "confidence": 0.92,
      "metadata": {
        "taste_match_score": 92,
        "popularity_rank": 5,
        "recency": "classic"
      }
    }
  ],
  "meta": {
    "request_id": "req_1699123456789",
    "timestamp": "2025-11-04T12:00:00Z",
    "processing_time_ms": 1243,
    "prompt_version": "v2.1",
    "total_results": 3,
    "tool_usage": {
      "total_tool_calls": 2,
      "tools_used": ["webSearch"],
      "tools_called": [
        {
          "tool_name": "webSearch",
          "arguments": {
            "query": "best sci-fi movies 2024 with philosophical themes",
            "numResults": 10,
            "type": "auto"
          },
          "timestamp": "2025-11-04T12:00:01Z"
        },
        {
          "tool_name": "webSearch",
          "arguments": {
            "query": "mind-bending action sci-fi films",
            "numResults": 10,
            "type": "auto"
          },
          "timestamp": "2025-11-04T12:00:03Z"
        }
      ]
    }
  }
}

2. POST /v1/explain

Generate detailed explanation for why a specific item matches user preferences.

Endpoint: POST https://api.tasteray.com/v1/explain

Request Body Schema

{
  "vertical": "string (required)",
  "item": {
    "name": "string (required)",
    "type": "string (required)",
    "metadata": {}
  },
  "context": {
    "user_preferences": ["string (conditional, required if profile not provided)"],
    "profile": "string (conditional, free-form user profile text)",
    "constraints": {}
  },
  "options": {
    "depth": "string (brief|detailed, default: detailed)",
    "include_alternatives": "boolean (default: false)",
    "language": "string (locale code, default: en_US)",
    "grounding": "boolean (enable web search, default: true)",
    "fast": "boolean (enable fast inference, default: false)"
  }
}

Response

Status: 200 OK

{
  "explanation": {
    "summary": "Your sanctuary. Anywhere you go.",
    "detailed_reasoning": {
      "taste_alignment": [
        "The world fades away. 30dB noise cancellation.",
        "Days of listening. 30-hour battery."
      ],
      "constraint_satisfaction": [
        "Flagship quality at $399. Right at your budget.",
        "Travel-ready by design. Quick-charge, foldable."
      ],
      "unique_factors": [
        "Travelers trust them. 91% recommend for commuting."
      ]
    },
    "potential_concerns": [
      "Over-ear, not in-ear. The trade-off for comfort."
    ],
    "alternatives": []
  },
  "confidence": 0.95,
  "meta": {
    "request_id": "req_1699123456790",
    "timestamp": "2025-11-04T12:05:00Z",
    "processing_time_ms": 876,
    "tool_usage": {
      "total_tool_calls": 1,
      "tools_used": ["webSearch"],
      "tools_called": [
        {
          "tool_name": "webSearch",
          "arguments": {
            "query": "Sony WH-1000XM5 reviews 2024 noise cancelling",
            "numResults": 10,
            "type": "auto"
          },
          "timestamp": "2025-11-04T12:05:01Z"
        }
      ]
    }
  }
}

3. GET /v1/health

Check API health status and service availability.

Endpoint: GET https://api.tasteray.com/v1/health

Authentication: Not required

Response

Status: 200 OK (Healthy) or 503 Service Unavailable (Unhealthy)

{
  "status": "healthy",
  "version": "1.0.0",
  "timestamp": "2025-11-04T12:00:00Z",
  "checks": {
    "ai_service": "ok",
    "langfuse": "ok",
    "kv_store": "ok"
  }
}

4. GET /v1/usage

Retrieve usage statistics for your API key.

Endpoint: GET https://api.tasteray.com/v1/usage

Response

Status: 200 OK

{
  "period": "current_month",
  "start_date": "2025-11-01T00:00:00Z",
  "end_date": "2025-11-30T23:59:59Z",
  "usage": {
    "requests_made": 2450,
    "requests_limit": 10000,
    "requests_remaining": 7550,
    "percentage_used": 24.5,
    "reset_date": "2025-12-01T00:00:00Z"
  },
  "breakdown_by_vertical": {
    "entertainment": 1200,
    "restaurant": 800,
    "product": 350,
    "travel": 100
  },
  "breakdown_by_day": [
    {"date": "2025-11-01", "requests": 120},
    {"date": "2025-11-02", "requests": 135}
  ],
  "tier": {
    "name": "Basic",
    "rate_limit": "50 requests/minute"
  }
}

Data Models

Vertical Types

The API is vertical-agnostic and supports any domain. Common verticals include:

Entertainment: movies, tv-series, books, music, podcasts, games, mobile-apps

Food & Dining: restaurants, cafes, bars, recipes, meal-kits

Travel: hotels, flights, destinations, activities, tours, cruises

Products: electronics, clothing, furniture, home-goods, beauty, sports

Services: courses, jobs, real-estate, healthcare, finance, fitness

Events: concerts, conferences, sports-events, theater, festivals

And many more: The API adapts to any vertical you specify.

Context Structure

All verticals share a common context structure. You can provide structured data OR free-form text:

interface RecommendationContext {
  // Provide EITHER structured preferences OR free-form profile (or both)
  preferences?: string[]  // User preferences (e.g., ["sci-fi", "action"])
  profile?: string  // Free-form text describing user profile/preferences

  constraints?: Record<string, any>  // Any constraints (budget, location, features)

  // Provide EITHER structured history OR free-form history_text (or both)
  history?: Array<{
    item: string  // Item name or identifier
    rating: string  // Flexible rating (e.g., "liked", "5 stars", "8/10")
    metadata?: Record<string, any>  // Optional context
  }>
  history_text?: string  // Free-form text describing user history
}

Flexibility: The API accepts either structured arrays or unstructured text. This makes it easy to:

  • Pass user profiles extracted from conversations or surveys
  • Import data from external systems without transformation
  • Combine structured data with free-form notes

Example Contexts by Vertical

Movies

{
  "preferences": ["sci-fi", "thriller", "thought-provoking"],
  "constraints": {
    "runtime_max": 150,
    "release_year_min": 2010,
    "platforms": ["Netflix", "HBO"]
  },
  "history": [
    {
      "item": "Inception",
      "rating": "loved",
      "metadata": {"year": 2010}
    }
  ]
}

Restaurants

{
  "preferences": ["Italian", "romantic", "authentic"],
  "constraints": {
    "location": "Seattle, WA",
    "price_range": "$$$",
    "dietary_restrictions": ["gluten-free options"]
  },
  "history": [
    {
      "item": "Canlis",
      "rating": "excellent",
      "metadata": {"occasion": "anniversary"}
    }
  ]
}

Products (Electronics)

{
  "preferences": ["wireless", "noise-cancelling", "long battery"],
  "constraints": {
    "category": "headphones",
    "budget_max": 300,
    "brand_preference": ["Sony", "Bose"]
  },
  "history": [
    {
      "item": "Sony WH-1000XM4",
      "rating": "9/10",
      "metadata": {"owned_for": "2 years"}
    }
  ]
}

Travel (Destinations)

{
  "preferences": ["beaches", "adventure", "culture"],
  "constraints": {
    "budget_total": 3000,
    "duration_days": 14,
    "region": "Southeast Asia",
    "season": "winter"
  },
  "history": [
    {
      "item": "Bali, Indonesia",
      "rating": "loved",
      "metadata": {"visited": "2023"}
    }
  ]
}

Supported Verticals

Vertical-Specific Guidelines

While the API is vertical-agnostic, here are best practices for common verticals:

Entertainment (movies, tv-series, books, music)

Preferences: Genres, themes, mood, pacing Constraints: Runtime, release year, platforms, content rating History: Previously watched/read items with ratings

Food & Dining (restaurants, recipes)

Preferences: Cuisine type, atmosphere, dietary focus Constraints: Location, price range, dietary restrictions, party size History: Past dining experiences with ratings

Travel (hotels, destinations, activities)

Preferences: Activity type, atmosphere, cultural interests Constraints: Budget, duration, location, season, accessibility History: Past trips with ratings and notes

Products (electronics, clothing, furniture)

Preferences: Features, style, brand preferences Constraints: Budget, category, specifications, compatibility History: Owned products with ratings and usage notes

Services (courses, jobs, healthcare)

Preferences: Skills to learn, career goals, specializations Constraints: Budget, time commitment, location, qualifications History: Past experiences with ratings


Building "For You" Experiences

TasteRay is designed for building personalized surfaces like "For You" tabs, feeds, and carousels.

"For You" Feeds

Create dynamic, personalized content feeds:

// Building a "For You" movie feed
const response = await fetch('https://api.tasteray.com/v1/recommend', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': apiKey
  },
  body: JSON.stringify({
    vertical: 'movies',
    context: {
      preferences: userProfile.preferences,
      history: userProfile.recentWatches.slice(0, 20)
    },
    options: {
      count: 20,
      explanation_depth: 'brief'
    }
  })
});

// Sort by taste_match_score for optimal ranking
const ranked = response.recommendations
  .sort((a, b) => b.metadata.taste_match_score - a.metadata.taste_match_score);

Personalized Carousels

Re-rank existing content based on user profiles:

// Personalize a category page
const response = await fetch('https://api.tasteray.com/v1/recommend', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
  body: JSON.stringify({
    vertical: 'products',
    items: categoryProducts, // Your existing product list
    context: { preferences: userProfile.preferences },
    options: { count: categoryProducts.length }
  })
});
// Items now ranked by personal relevance

Response Fields for "For You"

Field Use Case
metadata.taste_match_score Primary ranking signal (0-100)
metadata.mood_match Filter by mood context
confidence Secondary ranking signal (0.0-1.0)
explanation.why_match "Why you'll love it" tooltip
explanation.key_factors Expandable details section

Response Metadata and Tool Usage Tracking

All successful API responses include a meta object with request metadata and optional tool usage information.

Meta Object Structure

interface ResponseMeta {
  request_id: string;              // Unique identifier for the request
  timestamp: string;               // ISO 8601 timestamp of the response
  processing_time_ms?: number;     // Time taken to process the request (milliseconds)
  model?: string;                  // AI model identifier used
  prompt_version?: string;         // Version of the prompt template used
  total_results?: number;          // Number of recommendations returned
  tool_usage?: ToolUsageInfo;      // Information about tools/searches used (optional)
}

Tool Usage Tracking

When the grounding option is enabled (default for most requests), the API may use web search tools to gather real-time information. The tool_usage field provides full transparency about these searches:

interface ToolUsageInfo {
  total_tool_calls: number;        // Total number of tool calls made
  tools_used: string[];            // Names of tools used (e.g., ["webSearch"])
  tools_called?: ToolCallMetadata[];  // Details of each tool call (optional)
}

interface ToolCallMetadata {
  tool_name: string;               // Name of the tool that was called (e.g., "webSearch")
  arguments: Record<string, any>;  // Arguments passed to the tool
  timestamp: string;               // ISO 8601 timestamp of when the tool was called
}

Example Response with Tool Usage

{
  "meta": {
    "request_id": "req_1699123456789",
    "timestamp": "2025-11-04T12:00:00Z",
    "processing_time_ms": 2341,
    "prompt_version": "v2.1",
    "total_results": 3,
    "tool_usage": {
      "total_tool_calls": 2,
      "tools_used": ["webSearch"],
      "tools_called": [
        {
          "tool_name": "webSearch",
          "arguments": {
            "query": "best Italian restaurants San Francisco 2024",
            "numResults": 10,
            "type": "auto"
          },
          "timestamp": "2025-11-04T12:00:01Z"
        },
        {
          "tool_name": "webSearch",
          "arguments": {
            "query": "newly opened restaurants North Beach San Francisco",
            "numResults": 10,
            "type": "auto"
          },
          "timestamp": "2025-11-04T12:00:03Z"
        }
      ]
    }
  }
}

When Tool Usage is Included

  • Included: When options.grounding is true (default for most requests)
  • Not included: When options.grounding is false or when items are provided without explicit grounding enablement
  • Use cases:
    • Track what information sources were consulted for each recommendation
    • Monitor and analyze search patterns for debugging
    • Understand API usage for billing and optimization
    • Verify grounding quality and relevance

Error Handling

Error Response Format

All errors follow this structure:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": "Additional context about the error",
    "suggestion": "How to fix the error",
    "documentation_url": "/docs#error-handling"
  },
  "meta": {
    "request_id": "req_error_123",
    "timestamp": "2025-11-04T12:10:00Z"
  }
}

Common Error Codes

400 Bad Request

Code Description Solution
INVALID_VERTICAL Unsupported vertical Check supported verticals
MISSING_CONTEXT Required field missing Add required fields
INVALID_FORMAT Invalid JSON Validate JSON syntax
VALIDATION_ERROR Schema validation failed Check request schema

401 Unauthorized

Code Description Solution
INVALID_API_KEY Invalid or revoked API key Check/regenerate key
MISSING_API_KEY No API key provided Add X-API-Key header

403 Forbidden

Code Description Solution
INSUFFICIENT_PERMISSIONS No access to vertical Upgrade plan
QUOTA_EXCEEDED Monthly quota exceeded Upgrade plan or wait

429 Too Many Requests

Code Description Solution
RATE_LIMIT_EXCEEDED Rate limit exceeded Wait or upgrade plan

500 Internal Server Error

Code Description Solution
INTERNAL_ERROR Server error Retry after delay
AI_SERVICE_ERROR AI service error Retry after delay
PROMPT_ERROR Langfuse error Contact support

503 Service Unavailable

Code Description Solution
SERVICE_UNAVAILABLE Upstream service down Retry with backoff

504 Gateway Timeout

Code Description Solution
TIMEOUT Request timeout Simplify request

Code Examples

JavaScript/Node.js - Basic Request

const axios = require('axios');

async function getRecommendations() {
  try {
    const response = await axios.post(
      'https://api.tasteray.com/v1/recommend',
      {
        vertical: 'entertainment',
        context: {
          preferences: ['sci-fi', 'action', 'thought-provoking'],
          constraints: {
            runtime_max: 150
          }
        },
        options: {
          count: 3,
          explanation_depth: 'detailed'
        }
      },
      {
        headers: {
          'Content-Type': 'application/json',
          'X-API-Key': process.env.TASTERAY_API_KEY
        }
      }
    );

    console.log('Recommendations:', response.data.recommendations);
    return response.data;
  } catch (error) {
    if (error.response) {
      console.error('Error:', error.response.data.error);
    } else {
      console.error('Request failed:', error.message);
    }
  }
}

Python - Basic Request

import requests
import os

def get_recommendations():
    url = 'https://api.tasteray.com/v1/recommend'
    headers = {
        'Content-Type': 'application/json',
        'X-API-Key': os.environ.get('TASTERAY_API_KEY')
    }
    payload = {
        'vertical': 'restaurant',
        'context': {
            'preferences': ['Italian', 'romantic', 'authentic'],
            'constraints': {
                'location': 'Seattle, WA',
                'price_range': '$$$'
            }
        },
        'options': {
            'count': 3,
            'explanation_depth': 'detailed'
        }
    }

    try:
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        data = response.json()

        for rec in data['recommendations']:
            print(f"\n{rec['item']['name']}")
            print(f"Confidence: {rec['confidence'] * 100}%")
            print(f"Why: {rec['explanation']['why_match']}")

        return data
    except requests.exceptions.HTTPError as e:
        print(f"Error: {e.response.json()['error']}")

cURL - Multiple Examples

# Basic recommendation request
curl -X POST https://api.tasteray.com/v1/recommend \
  -H "Content-Type: application/json" \
  -H "X-API-Key: reco_live_your_api_key" \
  -d '{
    "vertical": "travel",
    "context": {
      "preferences": ["beaches", "adventure", "culture"],
      "constraints": {
        "budget_total": 3000,
        "duration_days": 14
      }
    },
    "options": {
      "count": 5
    }
  }'

# Explain endpoint
curl -X POST https://api.tasteray.com/v1/explain \
  -H "Content-Type: application/json" \
  -H "X-API-Key: reco_live_your_api_key" \
  -d '{
    "vertical": "product",
    "item": {
      "name": "Sony WH-1000XM5",
      "type": "headphones"
    },
    "context": {
      "user_preferences": ["noise-cancelling", "wireless"]
    }
  }'

# Check usage
curl https://api.tasteray.com/v1/usage \
  -H "X-API-Key: reco_live_your_api_key"

# Health check
curl https://api.tasteray.com/v1/health

Language Support Examples

# Spanish recommendations
curl -X POST https://api.tasteray.com/v1/recommend \
  -H "Content-Type: application/json" \
  -H "X-API-Key: reco_live_your_api_key" \
  -d '{
    "vertical": "entertainment",
    "context": {
      "preferences": ["sci-fi", "action"]
    },
    "options": {
      "count": 3,
      "language": "es_ES"
    }
  }'

# French explanation
curl -X POST https://api.tasteray.com/v1/explain \
  -H "Content-Type: application/json" \
  -H "X-API-Key: reco_live_your_api_key" \
  -d '{
    "vertical": "restaurants",
    "item": {
      "name": "Le Bernardin",
      "type": "fine_dining"
    },
    "context": {
      "user_preferences": ["seafood", "elegant"]
    },
    "options": {
      "language": "fr_FR"
    }
  }'

# Japanese recommendations
curl -X POST https://api.tasteray.com/v1/recommend \
  -H "Content-Type: application/json" \
  -H "X-API-Key: reco_live_your_api_key" \
  -d '{
    "vertical": "travel",
    "context": {
      "preferences": ["temples", "nature", "hot springs"]
    },
    "options": {
      "count": 5,
      "language": "ja_JP"
    }
  }'

Note: The language parameter accepts any valid locale code (e.g., en_US, es_ES, fr_FR, de_DE, ja_JP, zh_CN, pt_BR, it_IT). All AI-generated explanations and text will be in the specified language, while error messages remain in English.


Best Practices

1. Request Design

Keep Context Focused:

  • Provide 3-7 preferences (more isn't always better)
  • Only include relevant constraints
  • Limit history to recent/significant items (max 10-20)

Specify Constraints Clearly:

// Good
{"budget_max": 300, "category": "headphones"}

// Too vague
{"budget": "not too expensive"}

Use Appropriate Count:

  • 1-3 recommendations: Quick decisions
  • 3-5 recommendations: Standard use case
  • 5-10 recommendations: Exploratory browsing

2. Error Handling

Implement Retry Logic:

async function requestWithRetry(url, data, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await axios.post(url, data);
    } catch (error) {
      if (error.response?.status === 429) {
        const retryAfter = error.response.headers['retry-after'];
        await sleep(retryAfter * 1000);
      } else if (error.response?.status >= 500) {
        await sleep(Math.pow(2, i) * 1000); // Exponential backoff
      } else {
        throw error; // Don't retry client errors
      }
    }
  }
}

Check Rate Limits Proactively:

if (response.headers['x-ratelimit-remaining'] < 5) {
  console.warn('Approaching rate limit!');
  // Consider throttling requests
}

3. Performance Optimization

Use Structured Output:

  • Responses use Vercel AI SDK's structured output with Zod schemas
  • Automatic JSON validation and type safety
  • No need for manual parsing or error handling

Cache Recommendations:

  • Cache recommendations client-side when appropriate
  • Consider user session (don't cache forever)
  • Invalidate cache when preferences change

Batch Requests When Possible:

  • If generating multiple recommendations, use higher count
  • Single request is more efficient than multiple requests

4. Security

Protect API Keys:

  • Never expose keys in client-side code
  • Use environment variables
  • Rotate keys periodically
  • Use test keys for development

Validate User Input:

  • Sanitize user preferences before sending
  • Validate constraints client-side first
  • Set reasonable limits on history length

5. Monitoring

Track Usage:

// Periodically check usage
const usage = await checkUsage();
if (usage.percentage_used > 80) {
  notifyAdmin('Approaching quota limit');
}

Log Request IDs:

  • Save request_id from responses
  • Include in support tickets
  • Helps with debugging

6. Testing

Test with Various Inputs:

  • Test edge cases (empty constraints, max history)
  • Test error scenarios (invalid keys, malformed JSON)
  • Test different verticals

Use Test Keys:

  • Use reco_test_* keys for development
  • Switch to reco_live_* only for production

Architecture Notes

Stateless Design

The API is completely stateless:

  • No user profiles or sessions stored server-side
  • All context must be provided in each request
  • Enables unlimited horizontal scaling
  • Simplifies integration (no session management)

Edge Deployment

Deployed on Cloudflare Workers:

  • Global distribution (200+ locations)
  • Sub-50ms latency worldwide
  • Automatic scaling
  • No cold starts (V8 isolates)

AI Pipeline

  1. Request Validation: Zod schema validation
  2. Prompt Compilation: Langfuse fetches and compiles prompt template
  3. AI Generation: AI model generates recommendations
  4. Response Formatting: Structured JSON output
  5. Tracing: Langfuse logs traces for monitoring

Storage

Uses Cloudflare KV for:

  • API Keys: Hashed with SHA-256
  • Rate Limits: Sliding window counters (1-minute TTL)
  • Usage Stats: Aggregated hourly

Note: KV is eventually consistent (~60s propagation time)


Support & Resources


Changelog

All notable changes to the TasteRay Emotional API are documented below. The format is based on Keep a Changelog.

[Unreleased]

Added

  • Fast inference option for recommendations and explanations (2025-11-24)
  • Multi-model integration with automatic fallback (2025-11-24)
  • Test script for validating tool calling functionality (2025-11-24)

Changed

  • Enhanced AI service to support fast inference model selection (2025-11-24)
  • Updated API documentation for clearer description of fast inference option (2025-11-24)
  • Improved playground raw JSON visibility management for better UX (2025-11-24)
  • Refactored styles for a clean and minimal design across various components (2025-11-24)

[0.4.0] - 2025-11-16

Added

  • Tool choice parameter for AI services to control when external tools are used

Changed

  • Enhanced web search service with configurable tool choice options

[0.3.0] - 2025-11-15

Added

  • Web search integration for real-time information retrieval
  • Structured output support with tool usage tracking
  • Endpoint tab functionality in playground for better API exploration
  • Language support across recommendation and explanation endpoints
  • New recommendation formatting options (format_style, include_ratings)
  • New explanation options (explanation_depth, include_alternatives)
  • Comprehensive e-commerce examples for multiple verticals (fashion, electronics, furniture, hotels, travel, music, podcasts, TV series, recipes, fitness, online courses, apps, events, art)

Changed

  • Enhanced Langfuse prompt management and API response structure
  • Refactored AI service for improved tool call tracking
  • Enhanced documentation styles and layout
  • Updated brand styles across components
  • Refined API overview description in llms-txt endpoint
  • Refactored view imports and cleaned up unused files

Removed

  • Deprecated model references from documentation for clarity
  • Deprecated colors.css file to streamline brand styles

[0.2.0] - 2025-11-07

Added

  • Streaming support for explanations and recommendations with Server-Sent Events (SSE)
  • Playground interface for interactive API testing
  • Key generation interface for API key management
  • Markdown stripping functionality for cleaner text responses
  • Marked dependency for markdown processing

Changed

  • Updated AI service to use latest model version
  • Updated timeout settings in vitest.config.ts
  • Enhanced streaming response format in llms-txt endpoint
  • Updated support email to support@tasteray.com across all documentation
  • Updated API key signup links in documentation and routes
  • Switched package manager from npm to bun
  • Enhanced error handling in API responses
  • Standardized validation error messages for consistency

[0.1.1] - 2025-11-06

Changed

  • Updated dependencies to latest versions
  • Added Vitest testing scripts (snapshot, not fully tested)

[0.1.0] - 2025-11-05

Added

  • Initial release of TasteRay Emotional API
  • Multi-vertical recommendation engine powered by frontier AI
  • Langfuse integration for prompt management and tracing
  • Cloudflare Workers deployment with KV storage
  • API key authentication and management
  • Rate limiting with sliding window algorithm
  • Health check, recommend, explain, and usage endpoints
  • Comprehensive API documentation
  • Integration guides and examples

Version Summary

  • [0.4.0] - Tool choice parameters for AI services
  • [0.3.0] - Web search, structured output, multi-language support
  • [0.2.0] - Streaming support, playground interface, model updates
  • [0.1.1] - Dependencies and testing updates
  • [0.1.0] - Initial release

End of Documentation