# 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](#overview) 2. [Authentication](#authentication) 3. [Rate Limiting](#rate-limiting) 4. [API Endpoints](#api-endpoints) 5. [Data Models](#data-models) 6. [Supported Verticals](#supported-verticals) 7. [Building "For You" Experiences](#building-for-you-experiences) 8. [Error Handling](#error-handling) 9. [Code Examples](#code-examples) 10. [Best Practices](#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 ```http 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: ```http 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: ```json { "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 ```http Content-Type: application/json X-API-Key: reco_live_your_api_key_here ``` #### Request Body Schema ```json { "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` ```json { "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 ```json { "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` ```json { "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) ```json { "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` ```json { "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: ```typescript 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 // 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 // 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 ```json { "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 ```json { "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) ```json { "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) ```json { "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: ```javascript // 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: ```javascript // 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 ```typescript 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: ```typescript 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; // Arguments passed to the tool timestamp: string; // ISO 8601 timestamp of when the tool was called } ``` ### Example Response with Tool Usage ```json { "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: ```json { "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 ```javascript 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 ```python 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 ```bash # 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 ```bash # 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**: ```json // 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**: ```javascript 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**: ```javascript 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**: ```javascript // 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 - **Documentation**: /docs (HTML) or /llms.txt (plain text) - **Support Email**: hello@tasteray.com --- ## Changelog All notable changes to the TasteRay Emotional API are documented below. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### [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**