API Contract

Endpoint specifications, request/response schemas, and error handling

GET /v1/feed

Primary endpoint for fetching personalized video feeds. Returns a ranked list of videos tailored to the user's viewing history and engagement patterns.

Request Parameters

ParameterTypeRequiredDescription
user_idstringYesHashed user identifier (SHA-256, 64 chars)
tenant_idstringYesTenant identifier (host app)
limitintegerNoNumber of videos (default: 20, max: 100)
demographicsJSONNoOptional demographic hints (age_group, interests)
offsetintegerNoPagination offset (default: 0)

Example Request

curl -X GET "https://api.storyteller.com/v1/feed?user_id=06d6cbdcfc221d2f4460c17193442b9db221f30950f1c17af4e73e6e1788002b&tenant_id=tenant1&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Success Response (200 OK)

{
  "user_id": "06d6cbdcfc221d2f4460c17193442b9db221f30950f1c17af4e73e6e1788002b",
  "tenant_id": "tenant1",
  "personalized": true,
  "feed": [
    {
      "video_id": "vid_9k3m2l1a",
      "title": "Advanced Gaming Strategies",
      "thumbnail_url": "https://cdn.storyteller.com/thumbs/vid_9k3m2l1a.jpg",
      "duration_seconds": 180,
      "category": "gaming",
      "score": 0.89,
      "editorial_boost": 1.2,
      "created_at": "2026-01-10T14:30:00Z",
      "metadata": {
        "creator": "ProGamer123",
        "views": 125000,
        "likes": 8500
      },
      "ranking_reason": "High watch history match + editorial boost"
    },
    {
      "video_id": "vid_7j8k5n2b",
      "title": "eSports Tournament Highlights",
      "thumbnail_url": "https://cdn.storyteller.com/thumbs/vid_7j8k5n2b.jpg",
      "duration_seconds": 240,
      "category": "gaming",
      "score": 0.82,
      "editorial_boost": 1.0,
      "created_at": "2026-01-11T09:15:00Z",
      "metadata": {
        "creator": "ESportsDaily",
        "views": 250000,
        "likes": 15000
      },
      "ranking_reason": "Category affinity match"
    }
  ],
  "metadata": {
    "total_candidates": 1247,
    "response_time_ms": 142,
    "cache_hit": false,
    "algorithm_version": "v1.2.0",
    "ranking_weights": {
      "watch_history": 0.5,
      "engagement": 0.3,
      "editorial": 0.2
    }
  },
  "pagination": {
    "limit": 20,
    "offset": 0,
    "has_more": true
  }
}

GET /v1/feed/non-personalized

Fallback endpoint that returns editorial-curated content without personalization. Used when feature flag is disabled or as a kill switch fallback.

Request Parameters

ParameterTypeRequiredDescription
tenant_idstringYesTenant identifier
limitintegerNoNumber of videos (default: 20)

Example Response

{
  "tenant_id": "tenant1",
  "personalized": false,
  "feed": [
    {
      "video_id": "vid_1a2b3c4d",
      "title": "Editor's Pick: Top Video Today",
      "score": 1.5,
      "editorial_boost": 1.5
    }
  ],
  "metadata": {
    "response_time_ms": 45,
    "cache_hit": true,
    "algorithm_version": "editorial_only"
  }
}

Error Responses

400

Bad Request

Missing required parameters or invalid parameter values.

{
  "error": "Bad Request",
  "message": "Missing required parameter: user_id",
  "code": "MISSING_PARAMETER"
}
404

Not Found

Tenant ID not found or user has no accessible content.

{
  "error": "Not Found",
  "message": "Tenant not found: tenant999",
  "code": "TENANT_NOT_FOUND"
}
429

Too Many Requests

Rate limit exceeded (more than 3000 RPS).

{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Try again in 60 seconds.",
  "code": "RATE_LIMIT_EXCEEDED",
  "retry_after_seconds": 60
}
500

Internal Server Error

Unexpected server error. System will automatically fall back to non-personalized feed.

{
  "error": "Internal Server Error",
  "message": "An unexpected error occurred",
  "code": "INTERNAL_ERROR",
  "fallback_available": true
}
503

Service Unavailable

Service temporarily degraded. Kill switch activated or maintenance mode.

{
  "error": "Service Unavailable",
  "message": "Personalization service degraded. Using fallback.",
  "code": "SERVICE_DEGRADED",
  "fallback_enabled": true
}

Caching Headers

Responses include standard HTTP caching headers to enable CDN and client-side caching.

HeaderValuePurpose
Cache-Controlmax-age=60, privateCache for 60s, user-specific
ETag"06d6cbdcfc2..."Conditional requests
VaryAccept-EncodingVary by encoding
X-Cache-StatusHIT | MISSDebug cache performance
X-Response-Time142msMonitor latency

Rate Limiting

Rate limits are enforced per tenant to ensure fair usage and system stability.

Per-Tenant Limits

  • • 3,000 requests per second (peak burst)
  • • 600 requests per second (sustained average)
  • • Exceeded requests return 429 status code
  • • Rate limit resets every 60 seconds

Response Headers

X-RateLimit-Limit: 3000
X-RateLimit-Remaining: 2847
X-RateLimit-Reset: 1704985200