Documentation

Base URL: https://api.example.com. All responses are JSON.

Quick start

  1. Create an account at /register. You get 100 free points.
  2. Open API keys and create a key. Copy it right away: it is shown only once.
  3. Make a request:
curl https://api.example.com/v1/movie/550 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "success": true,
  "data": {
    "id": 550,
    "name": "Fight Club",
    "type": "movie",
    "url": "https://stream.example.com/movie/550.m3u8",
    "headers": {
      "Origin": "https://example.com",
      "Referer": "https://example.com/"
    }
  },
  "usage": {
    "cost": 5,
    "remaining_points": 95
  }
}

Authentication

Send your key in the Authorization header as a Bearer token. Keys start with kine_live_.

Authorization: Bearer kine_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are not accepted in the URL, because URLs end up in logs. Keep keys on your server. If a key leaks, revoke it on the API keys page; it stops working immediately.

Costs

RequestCost
Normal: Movie, TV5 points
Premium: Movie, TV (automatically determined by ID)10 points
Premium discovery (GET /v1/premium), Watch history, Search history, Account balanceFree
Invalid input, wrong scope, bad key, source not foundFree (refunded)

Points are reserved before upstream playback sources are resolved. If the title does not exist or the upstream source provider fails, points are refunded automatically and the response shows your balance. Each successful response includes usage.cost and usage.remaining_points.

Movie Playback Source

GET/v1/movie/{id}movie:read5 or 10 points

id is a positive whole number (the TMDB movie ID).

curl https://api.example.com/v1/movie/27205 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "success": true,
  "data": {
    "id": 27205,
    "name": "Inception",
    "type": "movie",
    "url": "https://stream.example.com/movie/27205.m3u8",
    "headers": {
      "Origin": "https://example.com",
      "Referer": "https://example.com/"
    }
  },
  "usage": { "cost": 5, "remaining_points": 95 }
}

TV Playback Source

GET/v1/tv/{id}tv:read5 or 10 points
GET/v1/tv/{id}/{season}/{episode}tv:read5 or 10 points

Request playback for a specific episode by passing season and episode in the URL.

curl https://api.example.com/v1/tv/1399/2/5 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "success": true,
  "data": {
    "id": 1399,
    "name": "Game of Thrones",
    "type": "tv",
    "season": 2,
    "episode": 5,
    "url": "https://stream.example.com/tv/1399.m3u8",
    "headers": {
      "Origin": "https://example.com",
      "Referer": "https://example.com/"
    }
  },
  "usage": { "cost": 5, "remaining_points": 95 }
}

Premium Titles

Premium status is determined automatically by the server based on the requested TMDB ID. Callers use the normal movie and TV endpoints:

Discover Premium Titles

GET/v1/premiumpremium:readFree

Returns the catalog of currently active premium titles:

{
  "success": true,
  "data": [
    { "id": 550, "name": "Fight Club", "type": "movie" },
    { "id": 1399, "name": "Game of Thrones", "type": "tv" }
  ]
}

Search History

POST/v1/search/historywatch:writeFree
curl -X POST https://api.example.com/v1/search/history \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "inception"}'

Nothing is saved if the user turned search history off in Settings. The response then says "saved": false.

Watch history

POST/v1/watchwatch:writeFree

Call it as playback progresses. One row is kept per movie or episode, and later calls update it. Progress of 90% or more (when duration is sent) marks the title as watched.

FieldTypeNotes
video_idintegerRequired.
video_typestringRequired: movie or tv.
video_namestringOptional, shown in the dashboard.
season, episodeintegerRequired for tv.
progressintegerSeconds watched.
durationintegerTotal seconds. Optional, used for the percentage.
watchedbooleanOptional. Force the watched flag.
curl -X POST https://api.example.com/v1/watch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"video_id": 1399, "video_type": "tv", "video_name": "Game of Thrones",
       "season": 1, "episode": 2, "progress": 600, "duration": 3000}'

Account balance

GET/v1/accountany keyFree
{
  "success": true,
  "data": {
    "points_balance": 95,
    "costs": { "normal": 5, "premium": 10 },
    "key": { "name": "My app", "prefix": "kine_live_ab12", "scopes": ["movie:read"] }
  }
}

Other public endpoints

GET/v1/packagesno auth
GET/healthno auth
GET/versionno auth

Errors

Errors always look like this:

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_POINTS",
    "message": "Not enough points for this request",
    "required": 5,
    "remaining": 2
  }
}
HTTPCodeMeaning
401MISSING_API_KEYNo Bearer token was sent.
401INVALID_API_KEYThe key does not exist.
401API_KEY_REVOKEDThe key was revoked.
402INSUFFICIENT_POINTSBalance is below the request cost. required and remaining are included. Nothing is charged.
403INSUFFICIENT_SCOPEThe key lacks the scope this endpoint needs.
403ACCOUNT_SUSPENDEDThe account is suspended.
404NOT_FOUNDNo title with that ID. Points are returned.
422VALIDATION_ERRORA parameter is missing or malformed. The field property names it.
429RATE_LIMITEDToo many requests. Wait for Retry-After seconds.
502UPSTREAM_ERRORThe data provider failed. Points are returned.
500INTERNAL_ERRORSomething went wrong on our side. Quote the X-Request-ID header if you contact support.

Rate limits

Each key can make 60 requests per minute. Every response carries:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1767225600   (unix time when the window resets)

When you go over, you get 429 with a Retry-After header. Requests rejected by the rate limiter never cost points.

Scopes

ScopeAllows
movie:readGET /v1/movie/{id}
tv:readGET /v1/tv/{id}, GET /v1/tv/{id}/{season}/{episode}
premium:readGET /v1/premium (discovery list)
watch:writePOST /v1/watch, POST /v1/search/history

Give each app a key with only the scopes it needs.

Payment webhooks

Payment providers notify the server at POST /v1/webhooks/payments. The request is accepted only if its signature is valid, so this endpoint is not for client use. Points are added only after the provider confirms the payment, never because the browser says so. Delivering the same event twice adds points once.