MENU navbar-image

Introduction

API for TV applications (Apple TV, Android TV) to display artworks.

Welcome to the 1Kosmos Factory TV API documentation.

This API is designed for TV applications to display artworks with QR codes for mobile scanning.

## Authentication
All requests require an `X-API-Key` header (shown on each endpoint below).

Endpoints that require a paired TV session also need an
`Authorization: Bearer <tv_access_token>` header. The TV access token is obtained from the
pairing flow: TV calls `GET /api/v1/tv/auth/qr`, displays the QR code, polls `POST /api/v1/tv/auth/poll`,
and the mobile app completes pairing via `POST /api/v1/tv/pair`.

`POST /api/v1/tv/pair` is called by the mobile app and requires the mobile user's bearer token.

## Rate Limiting
Default rate limit is 1000 requests per hour per API key.

<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).</aside>

Authenticating requests

To authenticate requests, include a X-API-Key header with the value "{YOUR_API_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

TV endpoints require an API key via the X-API-Key header. Endpoints marked "requires authentication" also need an Authorization: Bearer header with the TV access token returned by poll() (or the mobile user bearer token for pair()).

TV Artists

APIs for TV applications to display artist profiles. All endpoints require the X-API-Key header and a valid TV access token obtained from the TV pairing flow (Authorization: Bearer <tv_access_token>).

List Artists

requires authentication

Get a paginated list of artists for TV display. Returns basic profile info suitable for artist listing screens.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/artists?page=1&per_page=20" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/artists"
);

const params = {
    "page": "1",
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": [
        {
            "id": 5,
            "name": "John Doe",
            "profile_image": "https://example.com/artists/5/photo.jpg",
            "specialty": "Oil Painting",
            "permanent_location": "Rajkot, Gujarat, India"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 3,
        "per_page": 20,
        "total": 55
    }
}
 

Request      

GET api/v1/tv/artists

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

page   integer  optional    

Page number for pagination. Default: 1. Example: 1

per_page   integer  optional    

Number of items per page. Min: 1, Max: 50. Default: 20. Example: 20

Get Artist

requires authentication

Get a single artist by ID for TV display. Includes full profile details, bio, permanent location, social links, and career sections (education, exhibitions, galleries, residencies, institutions).

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/artists/5" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/artists/5"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": {
        "id": 5,
        "name": "John Doe",
        "profile_image": "https://example.com/artists/5/photo.jpg",
        "bio": "Contemporary artist based in Rajkot.",
        "specialty": "Oil Painting",
        "years_of_experience": 10,
        "permanent_location": "Rajkot, Gujarat, India",
        "social_links": {
            "instagram": "https://instagram.com/johndoe",
            "facebook": null,
            "website": "https://johndoe.art",
            "twitter": null
        },
        "education": [
            {
                "name": "Fine Arts Academy",
                "date": "2010",
                "location": "Mumbai, India"
            }
        ],
        "exhibitions": [
            {
                "name": "Modern Art Expo",
                "date": "2022",
                "location": "Delhi, India"
            }
        ],
        "galleries": [
            {
                "name": "City Gallery",
                "date": "2021",
                "location": "Ahmedabad, India"
            }
        ],
        "residencies": [
            {
                "name": "Artist Residency Program",
                "date": "2019",
                "location": "Jaipur, India"
            }
        ],
        "institutions": [
            {
                "name": "National Institute of Art",
                "date": "2018",
                "location": "Baroda, India"
            }
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\User] 999"
}
 

Request      

GET api/v1/tv/artists/{id}

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The artist user ID. Example: 5

Subscribe to an artist

requires authentication

Subscribe the authenticated TV user to an artist. Allows the user to filter artworks by subscribed artists.

Example request:
curl --request POST \
    "https://stage.1kosmosfactory.com/api/v1/tv/artists/5/subscribe" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/artists/5/subscribe"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (201, Success):


{
    "message": "Subscribed successfully",
    "artist_id": 5,
    "is_subscribed": true
}
 

Example response (422, Already Subscribed):


{
    "message": "Already subscribed to this artist"
}
 

Request      

POST api/v1/tv/artists/{id}/subscribe

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The artist user ID. Example: 5

Unsubscribe from an artist

requires authentication

Unsubscribe the authenticated TV user from an artist.

Example request:
curl --request DELETE \
    "https://stage.1kosmosfactory.com/api/v1/tv/artists/5/subscribe" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/artists/5/subscribe"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "message": "Unsubscribed successfully",
    "artist_id": 5,
    "is_subscribed": false
}
 

Example response (422, Not Subscribed):


{
    "message": "Not subscribed to this artist"
}
 

Request      

DELETE api/v1/tv/artists/{id}/subscribe

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The artist user ID. Example: 5

Get user's subscribed artists

requires authentication

Get a paginated list of artists the authenticated TV user is subscribed to.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/me/artist-subscriptions?page=1&per_page=20" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/me/artist-subscriptions"
);

const params = {
    "page": "1",
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": [
        {
            "id": 5,
            "name": "John Doe",
            "profile_image": "https://example.com/artists/5/photo.jpg",
            "specialty": "Oil Painting",
            "permanent_location": "Rajkot, Gujarat, India",
            "is_subscribed": true
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 20,
        "total": 3
    }
}
 

Request      

GET api/v1/tv/me/artist-subscriptions

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

page   integer  optional    

Page number for pagination. Default: 1. Example: 1

per_page   integer  optional    

Number of items per page. Min: 1, Max: 50. Default: 20. Example: 20

Get user's category preferences

requires authentication

Get the authenticated TV user's selected category preferences. Returns the list of categories the user has selected for filtering artworks.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/me/category-preferences" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/me/category-preferences"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": {
        "categories": [
            {
                "id": 1,
                "name": "Painting",
                "slug": "painting",
                "description": "Oil and acrylic paintings"
            },
            {
                "id": 2,
                "name": "Photography",
                "slug": "photography",
                "description": "Digital and film photography"
            }
        ],
        "category_ids": [
            1,
            2
        ]
    }
}
 

Request      

GET api/v1/tv/me/category-preferences

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Update user's category preferences

requires authentication

Update the authenticated TV user's category preferences. The user can select which categories they want to see artworks from. At least one category must be selected.

Example request:
curl --request PUT \
    "https://stage.1kosmosfactory.com/api/v1/tv/me/category-preferences" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"category_ids\": [
        1,
        2,
        3
    ]
}"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/me/category-preferences"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "category_ids": [
        1,
        2,
        3
    ]
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Success):


{
    "data": {
        "categories": [
            {
                "id": 1,
                "name": "Painting",
                "slug": "painting",
                "description": "Oil and acrylic paintings"
            }
        ],
        "category_ids": [
            1
        ]
    },
    "message": "Preferences updated successfully"
}
 

Example response (422, Validation Error):


{
    "message": "The given data was invalid.",
    "errors": {
        "category_ids": [
            "The category_ids field is required."
        ]
    }
}
 

Request      

PUT api/v1/tv/me/category-preferences

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

category_ids   string[]     

Array of category IDs to select.

TV Artworks

APIs for TV applications to display artworks with QR codes. All endpoints require the X-API-Key header and a valid TV access token obtained from the TV pairing flow (Authorization: Bearer <tv_access_token>).

List Artworks

requires authentication

Get a paginated list of artworks for TV display. Each artwork includes images and a QR code that links to the artwork detail page in the mobile/web application.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/artworks?page=1&per_page=20&category_id=1&featured=1&sort=new" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/artworks"
);

const params = {
    "page": "1",
    "per_page": "20",
    "category_id": "1",
    "featured": "1",
    "sort": "new",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "title": "Sunset Canvas",
            "description": "A beautiful sunset painting",
            "artist_name": "John Doe",
            "images": [
                {
                    "image_url": "https://example.com/artworks/1/image.jpg"
                }
            ],
            "qr_code": {
                "url": "https://stage.1kosmosfactory.com/web/artist/artwork-detail?id=1",
                "base64": "data:image/svg+xml;base64,PHN2ZyB..."
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 20,
        "total": 100
    }
}
 

Request      

GET api/v1/tv/artworks

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

page   integer  optional    

Page number for pagination. Default: 1. Example: 1

per_page   integer  optional    

Number of items per page. Min: 1, Max: 50. Default: 20. Example: 20

category_id   integer  optional    

Filter by category ID. Example: 1

featured   boolean  optional    

Show only featured artworks. Example: true

sort   string  optional    

Sort order: new, popular, price_asc, price_desc. Default: new. Example: new

Get Artwork

requires authentication

Get a single artwork by ID for TV display. Includes full details, images, artist info, category, and a QR code that links to the artwork detail page.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/artworks/1" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/artworks/1"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": {
        "id": 1,
        "title": "Sunset Canvas",
        "description": "A beautiful sunset painting with vibrant colors",
        "artist_name": "John Doe",
        "views_count": 15,
        "images": [
            {
                "id": 456,
                "image_url": "https://example.com/artworks/1/image.jpg"
            }
        ],
        "artist": {
            "id": 5,
            "first_name": "John",
            "last_name": "Doe",
            "full_name": "John Doe",
            "profile_image": "https://example.com/artist.jpg",
            "bio": "Contemporary artist specializing in abstract paintings"
        },
        "category": {
            "id": 3,
            "name": "Painting",
            "slug": "painting",
            "description": "Oil and acrylic paintings"
        },
        "owner": {
            "id": 6,
            "first_name": "Jane",
            "last_name": "Smith",
            "full_name": "Jane Smith",
            "profile_image": "https://example.com/collector.jpg"
        },
        "qr_code": {
            "url": "https://stage.1kosmosfactory.com/web/artist/artwork-detail?id=1",
            "base64": "data:image/png;base64,iVBORw0KGgo..."
        }
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\Artwork] 999"
}
 

Request      

GET api/v1/tv/artworks/{id}

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The artwork ID. Example: 1

TV Authentication

Endpoints for pairing a TV device with a mobile user account. QR and poll endpoints require only the X-API-Key header. The pair endpoint requires an authenticated user bearer token from the mobile/Flutter app.

Pair TV From Mobile App

Called by the authenticated mobile/Flutter app after scanning the TV QR code. Links the pairing session to the authenticated user.

Note: This endpoint requires the mobile user's bearer token (regular Sanctum auth), NOT the TV access token, and does NOT require an X-API-Key.

Example request:
curl --request POST \
    "https://stage.1kosmosfactory.com/api/v1/tv/pair" \
    --header "Authorization: Bearer {mobile_user_bearer_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"session_code\": \"ABCDEF12\"
}"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/pair"
);

const headers = {
    "Authorization": "Bearer {mobile_user_bearer_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "session_code": "ABCDEF12"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Success):


{
    "message": "TV paired successfully.",
    "session_code": "ABCDEF12"
}
 

Example response (404, Invalid or Expired):


{
    "message": "Invalid or expired session code."
}
 

Request      

POST api/v1/tv/pair

Headers

Authorization        

Example: Bearer {mobile_user_bearer_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

session_code   string     

The pairing session code from the scanned QR code. Example: ABCDEF12

Generate QR Session

Creates a new TV pairing session and returns a QR code URL. The TV application should display the QR code and begin polling POST /api/v1/tv/auth/poll until the user scans and pairs.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/auth/qr" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/auth/qr"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "session_code": "ABCDEF12",
    "qr_url": "onekosmosfactory://tv-pair?code=ABCDEF12",
    "expires_at": "2026-06-26T21:00:00+00:00"
}
 

Request      

GET api/v1/tv/auth/qr

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Poll Pairing Status

Polls the status of a TV pairing session. Returns 202 while waiting, 200 once paired with the TV access token, 404 if the session is not found, and 410 if the session expired.

Example request:
curl --request POST \
    "https://stage.1kosmosfactory.com/api/v1/tv/auth/poll" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"session_code\": \"ABCDEF12\"
}"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/auth/poll"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "session_code": "ABCDEF12"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Paired):


{
    "access_token": "1|tv_access_token...",
    "user": {
        "id": 5,
        "full_name": "John Doe",
        "email": "john@example.com"
    },
    "subscription": {
        "has_tv_access": true,
        "plan_name": "Basic",
        "billing_interval": "yearly",
        "ends_at": "2027-06-26T21:00:00+00:00",
        "artwork_limit": 25
    }
}
 

Example response (202, Waiting):


{
    "message": "Waiting for pairing."
}
 

Example response (404, Not Found):


{
    "message": "Session not found."
}
 

Example response (410, Expired):


{
    "message": "Session expired."
}
 

Request      

POST api/v1/tv/auth/poll

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

session_code   string     

The pairing session code shown in the QR code. Example: ABCDEF12

TV Me

Endpoints for the authenticated TV device to retrieve information about the currently paired user. Requires a valid TV access token returned by the pairing flow.

Get TV Subscription

requires authentication

Returns the paired user's subscription status for TV access checks. Does not require an active TV subscription plan, but the paired session must be valid.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/me/subscription" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/me/subscription"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": {
        "has_tv_access": true,
        "plan_name": "Basic",
        "billing_interval": "yearly",
        "ends_at": "2027-06-26T21:00:00+00:00",
        "artwork_limit": 25
    }
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/tv/me/subscription

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

TV Subscriptions

Endpoints for the authenticated TV device to browse membership plans and subscribe via native in-app purchase platforms. All endpoints require a valid TV access token returned by the pairing flow.

List available subscription plans

requires authentication

Returns active plans with web prices and platform-specific product IDs (Apple/Google/Amazon) that the TV app must use when calling the native in-app purchase SDK.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/plans" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/plans"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "slug": "basic",
            "name": "Basic",
            "monthly_price": {
                "currency": "USD",
                "price": "9.99"
            },
            "yearly_price": {
                "currency": "USD",
                "price": "99.99"
            },
            "all_prices": {
                "USD": {
                    "monthly": "9.99",
                    "yearly": "99.99"
                }
            },
            "platform_products": [
                {
                    "id": 1,
                    "platform": "apple",
                    "billing_interval": "monthly",
                    "product_id": "com.1kosmosfactory.basic.monthly",
                    "is_active": true
                }
            ],
            "is_current": false
        }
    ],
    "currency": "USD"
}
 

Request      

GET api/v1/tv/plans

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Verify an Apple In-App Purchase subscription

requires authentication

The TV app sends the signed transaction info (JWS) after a successful StoreKit 2 purchase. The backend decodes and verifies the JWS, looks up the matching plan from the configured platform products, and activates the subscription.

Example request:
curl --request POST \
    "https://stage.1kosmosfactory.com/api/v1/tv/subscriptions/verify-apple" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"signedTransactionInfo\": \"eyJhbGciOiJFUzI1NiIs...\"
}"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/subscriptions/verify-apple"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIs..."
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Success):


{
    "message": "Subscription verified and activated.",
    "data": {
        "has_tv_access": true,
        "plan_name": "Basic",
        "billing_interval": "monthly",
        "ends_at": "2026-08-15T12:00:00+00:00",
        "artwork_limit": 0
    }
}
 

Request      

POST api/v1/tv/subscriptions/verify-apple

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

signedTransactionInfo   string     

The signed JWS transaction info from StoreKit 2. Example: eyJhbGciOiJFUzI1NiIs...

Get the current TV subscription

requires authentication

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/subscriptions/current" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/subscriptions/current"
);

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
    "data": {
        "has_tv_access": true,
        "plan_name": "Basic",
        "billing_interval": "monthly",
        "ends_at": "2026-08-15T12:00:00+00:00",
        "artwork_limit": 0
    }
}
 

Request      

GET api/v1/tv/subscriptions/current

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

List TV subscription history

requires authentication

Returns paginated subscription history for the authenticated TV user.

Example request:
curl --request GET \
    --get "https://stage.1kosmosfactory.com/api/v1/tv/subscriptions/history?per_page=20" \
    --header "X-API-Key: {YOUR_API_KEY}" \
    --header "Authorization: Bearer {tv_access_token}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://stage.1kosmosfactory.com/api/v1/tv/subscriptions/history"
);

const params = {
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "X-API-Key": "{YOUR_API_KEY}",
    "Authorization": "Bearer {tv_access_token}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Success):


{
  "data": [...],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 20,
    "total": 1
  }
}
 

Request      

GET api/v1/tv/subscriptions/history

Headers

X-API-Key        

Example: {YOUR_API_KEY}

Authorization        

Example: Bearer {tv_access_token}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

optional Number of records per page (1-50). Default: 20. Example: 20