Koopi Developer API
Build on top of Koopi. The REST API powers the viewer experience, the creator upload pipeline, and platform automation over predictable JSON endpoints.
Introduction
The Koopi API is organized around REST. It has predictable resource-oriented URLs, accepts and returns JSON-encoded payloads, and uses standard HTTP response codes, verbs, and authentication. All endpoints are served from the same origin as the application.
Resource-oriented
Predictable URLs grouped by resource such as coins, series, and uploads.
JSON everywhere
Requests and responses use JSON with UTF-8 encoding.
Token & session auth
Use a scoped API token for automation, or a secure session cookie in the browser.
Standard semantics
Conventional HTTP verbs and status codes for every operation.
Base URL
All API routes are relative to your Koopi deployment origin. Prefix every path below with your base URL.
https://koopi.tv/apiAuthentication
Koopi supports two ways to authenticate. In the browser, requests use a secure, HTTP-only session cookie issued at sign-in. For scripts, CI pipelines, and integrations, use an API token sent as a Bearer credential. Each endpoint declares one of three access levels:
No authentication required.
Requires a signed-in viewer. Returns 401 otherwise.
Requires a creator account. Authenticate with a session cookie or an API token holding the required scope. Returns 401 without valid credentials and 403 when the account is not a creator or the token is missing a required scope.
API tokens
Creators can mint API tokens from the token dashboard or the Creator Hub. A token is shown only once at creation — Koopi stores just a hash, so copy it immediately. Pass it in the Authorization header:
curl https://koopi.tv/api/creator-hub/series \
-H "Authorization: Bearer koopi_sk_xxxxxxxxxxxxxxxxxxxx"Each token is granted one or more scopes. A request to a creator endpoint is rejected with 403 if the token lacks the scope that endpoint requires. Tokens may optionally expire and can be revoked at any time.
| Scope | Grants |
|---|---|
| read | Read your series, episodes, and performance data. |
| upload | Request pre-signed upload URLs and push new video/image assets. |
| write | Register episodes and update content metadata. |
Requests & Responses
Send request bodies as JSON with a Content-Type: application/json header. Path parameters are shown in braces, for example /api/creator-hub/series/{id}. Successful responses return a 2xx status with a JSON body.
Errors
Koopi uses conventional HTTP status codes. Failures return a JSON body with an error message.
| Status | Meaning |
|---|---|
| 200 / 201 | The request succeeded. |
| 400 | Malformed request or missing required parameters. |
| 401 | Not authenticated — sign in and retry. |
| 403 | Authenticated but lacking the required (creator) access. |
| 404 | The requested resource does not exist. |
| 429 | Too many requests — slow down and retry later. |
| 5xx | An unexpected error occurred on the server. |
401 Unauthorized
{
"error": "Unauthorized"
}Rate Limits
Endpoints are rate limited to protect platform stability. If you exceed the limit you will receive a429 response; back off and retry with exponential delay. Upload part-signing requests are batched to minimize round trips.
Coins & Wallet
Read a viewer’s coin balance and spend coins to unlock episodes or skip advertising.
/api/coins/balanceUserReturn the authenticated viewer’s current coin balance.
{
"coin_balance": 240
}/api/coins/settingsUserFetch the coin pricing table and auto-skip configuration for the current account.
/api/coins/deductUserSpend coins to unlock a locked episode or skip an ad break.
| Parameter | Type | Description |
|---|---|---|
| amount* | integer | Number of coins to deduct. Must be positive. |
| reason* | string | One of `unlock_episode` or `skip_ad`. |
| episodeId | string | Sanity document id of the episode being unlocked. |
POST /api/coins/deduct
{
"amount": 30,
"reason": "unlock_episode",
"episodeId": "ep_9f2c..."
}/api/coins/auto-skipUserEnable or disable automatically spending coins to skip ads.
| Parameter | Type | Description |
|---|---|---|
| enabled* | boolean | Whether auto-skip is turned on. |
Watchlist
Manage the series a viewer has saved to watch later.
/api/watchlistUserList every series in the viewer’s watchlist.
/api/watchlistUserAdd or remove a series from the watchlist.
| Parameter | Type | Description |
|---|---|---|
| seriesId* | string | Sanity document id of the series. |
| action* | string | Either `add` or `remove`. |
Watch History
Track and resume playback progress across episodes.
/api/watch-historyUserReturn recently watched episodes with resume positions.
/api/watch-historyUserRecord playback progress for an episode.
| Parameter | Type | Description |
|---|---|---|
| episodeId* | string | Episode being watched. |
| positionSeconds* | number | Current playhead position in seconds. |
| completed | boolean | Set true when the episode finished playing. |
Leaderboard
Public ranking data for games and creators.
/api/leaderboardPublicReturn the top-ranked entries. Supports optional filtering by game.
| Parameter | Type | Description |
|---|---|---|
| gameId | string | Restrict results to a single game. |
| limit | integer | Maximum entries to return (default 50). |
Series & Episodes
Creator-scoped read access to the series catalog and their episodes.
/api/creator-hub/seriesCreatorList all series owned by the authenticated creator.
/api/creator-hub/series/{id}CreatorFetch a single series with its metadata.
| Parameter | Type | Description |
|---|---|---|
| id* | string | Series document id (path parameter). |
/api/creator-hub/series/{id}/episodesCreatorList every episode belonging to a series, including processing status.
| Parameter | Type | Description |
|---|---|---|
| id* | string | Series document id (path parameter). |
/api/creator-hub/episode/{id}CreatorDelete an episode. Used to abandon a source that failed or is still processing.
| Parameter | Type | Description |
|---|---|---|
| id* | string | Episode document id (path parameter). |
Media Uploads
Upload video sources and thumbnails to storage, then register them for transcoding. Large files (over 100 MB) use S3 multipart uploads for resilient, parallel transfer up to 200 GB.
/api/creator-hub/presignCreatorGet a pre-signed PUT URL for a single-request upload of a small video file.
| Parameter | Type | Description |
|---|---|---|
| seriesId* | string | Owning series. |
| episodeTitle* | string | Title used to derive the object key. |
| filename* | string | Original file name. |
| contentType* | string | MIME type, e.g. `video/mp4`. |
/api/creator-hub/presign-imageCreatorGet a pre-signed PUT URL for uploading a thumbnail or cover image.
/api/creator-hub/multipart/createCreatorBegin a multipart upload. Returns the object key and an uploadId for the session.
POST /api/creator-hub/multipart/create
{
"seriesId": "series_1a2b...",
"episodeTitle": "Beard Talk — Episode 4",
"filename": "beard-talk-04.mp4",
"contentType": "video/mp4",
"isLongForm": true
}
→ 200 OK
{
"key": "koopi-series/.../beard-talk-04.mp4",
"uploadId": "2~aBc..."
}/api/creator-hub/multipart/sign-partsCreatorReturn pre-signed PUT URLs for a batch of part numbers within an active upload.
| Parameter | Type | Description |
|---|---|---|
| key* | string | Object key from `create`. |
| uploadId* | string | Multipart upload id. |
| partNumbers* | integer[] | Part numbers to sign (1-indexed). |
/api/creator-hub/multipart/completeCreatorFinalize a multipart upload. Part ETags are collected server-side, so no ETag headers are required from the client.
| Parameter | Type | Description |
|---|---|---|
| key* | string | Object key from `create`. |
| uploadId* | string | Multipart upload id. |
| expectedParts* | integer | Number of parts uploaded, used to validate completeness. |
/api/creator-hub/multipart/abortCreatorCancel an in-progress multipart upload and discard any uploaded parts.
| Parameter | Type | Description |
|---|---|---|
| key* | string | Object key from `create`. |
| uploadId* | string | Multipart upload id. |
/api/creator-hub/register-episodeCreatorRegister an uploaded source as an episode and submit it to the transcoding pipeline. Playback becomes available once processing completes.
| Parameter | Type | Description |
|---|---|---|
| seriesId* | string | Owning series. |
| s3Key* | string | Object key of the uploaded source. |
| episodeTitle* | string | Display title. |
| isLongForm | boolean | Whether this is a long-form source for the clipper. |
AI Clipper
Analyze a long-form source and generate short vertical clips from it.
/api/creator-hub/clipper/analyze-cutsCreatorDetect candidate cut points and highlight moments in a source.
/api/creator-hub/clipper/analyze-segmentsCreatorGroup transcript segments into coherent clip suggestions.
/api/creator-hub/clipper/analyze-framingCreatorSuggest vertical framing / crop windows for a clip.
/api/creator-hub/clipper/shortsCreatorList generated shorts for a source.
/api/creator-hub/clipper/shorts/{id}CreatorDelete a generated short.
| Parameter | Type | Description |
|---|---|---|
| id* | string | Short document id (path parameter). |
Games
Register playable game bundles and manage play sessions.
/api/games/registerCreatorRegister an uploaded game bundle.
/api/games/presignCreatorGet a pre-signed URL to upload a game bundle archive.
/api/games/bundle-urlUserResolve a signed, time-limited URL to load a game bundle.
/api/games/sessionUserStart or update a game play session.
/api/games/toggle-ad-freeUserToggle ad-free play using coins.
Advertising
Serve advertisements and record impression / interaction telemetry.
/api/ads/randomPublicReturn a randomly selected eligible advertisement.
/api/ads/impressionPublicRecord that an ad was shown.
| Parameter | Type | Description |
|---|---|---|
| adId* | string | Advertisement id. |
/api/ads/eventPublicRecord an ad interaction such as a click or skip.
| Parameter | Type | Description |
|---|---|---|
| adId* | string | Advertisement id. |
| type* | string | Event type, e.g. `click` or `skip`. |
Webhooks
Inbound endpoints invoked by external services. These are not called by your integration — they are secured by provider signatures and documented here for completeness.
/api/webhooks/muxPublicReceives transcoding lifecycle events (asset ready, errored, track ready). Verified with the Mux signing secret.
/api/webhooks/s3PublicReceives storage notifications for uploaded objects.
/api/stripe/webhookPublicReceives Stripe payment and checkout events. Verified with the Stripe signing secret.