Developers
Developer APIs
Strimm exposes two HTTP APIs for apps and integrations. Use the REST API for new integrations
with a { success, data } envelope. Use the Custom Services API for
the bundled mobile app template and other legacy-compatible clients that expect a { data } envelope.
Claude, ChatGPT, and Grok should use the hosted
MCP server
instead of calling these APIs directly.
REST API
Token-based API for studio-authenticated apps. Login with username or email, then send the GUID auth token on protected routes.
Base URL
https://newlook2.strimm.com/api/v1/rest
Response envelope
Successful responses:
{
"success": true,
"data": { ... }
}
Error responses:
{
"success": false,
"error": {
"code": "invalid_credentials",
"message": "Login failed."
}
}
Authentication
/auth/login
No auth required. Accepts username or email and password.
Request body
{
"username": "your_username",
"password": "your_password"
}
Response data
{
"authToken": "00000000-0000-0000-0000-000000000000",
"userId": 123,
"userName": "creator",
"email": "creator@example.com",
"publicUrl": "creator"
}
/auth/logout
Revokes the Bearer token sent in the Authorization header.
Apps
/apps/{platform}
Returns app configuration for the authenticated user. Platforms:
mobile, roku, firetv, appletv, androidtv (case-insensitive).
Example request
GET /api/v1/rest/apps/mobile
Authorization: Bearer {authToken}
Example response
{
"success": true,
"data": {
"appId": 1,
"platform": "Mobile",
"appName": "My Network App",
"channelTubeIds": [42, 58],
"isPaid": true,
"storeProducts": [
{
"storePlatform": "Apple",
"productId": "com.yourbrand.app.weekly",
"displayName": "Weekly access",
"billingPeriod": "Weekly",
"isActive": true,
"storeSharedSecretConfigured": false
},
{
"storePlatform": "Apple",
"productId": "com.yourbrand.app.monthly",
"displayName": "Monthly access",
"billingPeriod": "Monthly",
"isActive": true,
"storeSharedSecretConfigured": false
},
{
"storePlatform": "Apple",
"productId": "com.yourbrand.app.yearly",
"displayName": "Yearly access",
"billingPeriod": "Yearly",
"isActive": true,
"storeSharedSecretConfigured": false
},
{
"storePlatform": "Google",
"productId": "com.yourbrand.app.monthly",
"displayName": "Monthly access",
"billingPeriod": "Monthly",
"isActive": true,
"storeSharedSecretConfigured": false
}
],
"vodPpv": {
"isEnabled": true,
"accessDurationHours": 48,
"storeProducts": [
{
"storePlatform": "Apple",
"productId": "com.yourbrand.app.vod",
"displayName": "Unlock VOD",
"billingPeriod": "OneTime",
"isActive": true,
"storeSharedSecretConfigured": false
},
{
"storePlatform": "Google",
"productId": "com.yourbrand.app.vod",
"displayName": "Unlock VOD",
"billingPeriod": "OneTime",
"isActive": true,
"storeSharedSecretConfigured": false
}
]
},
"mobile": {
"appSlug": "my-network",
"logoUrl": "/api/v1/services/custom/users/123/apps/mobile/assets/logo?v=638500000000000000",
"logoBlobKey": "db:logo",
"iconUrl": "/api/v1/services/custom/users/123/apps/mobile/assets/icon?v=638500000000000000",
"iconBlobKey": "db:icon",
"selectionColor": "FF5722",
"headerFooterColor": "212121",
"backgroundColor": "000000",
"fontColor": "FFFFFF",
"about": "Welcome to my channel network.",
"copyrightPolicyLink": null,
"gdprLink": null,
"supportEmail": "support@example.com",
"faqLink": null,
"termsLink": null,
"privacyPolicyLink": "https://example.com/privacy",
"instagram": null,
"facebook": null,
"twitter": null
},
"roku": null,
"fireTv": null,
"appleTv": null,
"androidTv": null
}
}
Only the platform-specific object is populated (mobile, roku, fireTv, appleTv, or androidTv).
The others are null.
storeProducts lists every paid subscription SKU for the app
(weekly / monthly / yearly per store). Multiple rows per store are allowed.
vodPpv remains one one-time SKU per store for VOD unlocks.
Prices are configured in App Store Connect / Google Play — Strimm stores Product IDs only.
Channels
/channels
Lists all channels owned by the authenticated user, each including its video library and any platform-specific VAST ad settings that have been configured.
Example response
{
"success": true,
"data": [
{
"channelTubeId": 42,
"name": "Main Channel",
"url": "main-channel",
"categoryName": "Entertainment",
"pictureUrl": "https://cdn.example.com/tubestrimm/123/channel.jpg",
"description": "My flagship channel.",
"order": 1,
"videos": [
{
"videoTubeId": 1001,
"title": "Intro to the Network",
"description": "A quick overview.",
"durationSeconds": 185.5,
"thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
"providerVideoId": "dQw4w9WgXcQ",
"providerName": "YouTube",
"categoryName": "Promo"
},
{
"videoTubeId": 1002,
"title": "Behind the Scenes",
"description": null,
"durationSeconds": 612,
"thumbnailUrl": "https://cdn.example.com/tubestrimm/123/thumb.jpg",
"providerVideoId": "abc123",
"providerName": "Custom",
"categoryName": "Documentary"
}
],
"vastSettings": [
{
"platform": "web",
"vastUrl": "https://ads.example.com/vast?channel=42&platform=web",
"vastVersion": 1,
"skippable": true,
"adFrequency": 1,
"midRollFrequency": 10,
"slottable": false,
"timeFrom": null,
"timeTo": null,
"vastType": "fullscreen",
"allowAdsInVod": false
},
{
"platform": "roku",
"vastUrl": "https://ads.example.com/vast?channel=42&platform=roku",
"vastVersion": 1,
"skippable": false,
"adFrequency": 1,
"midRollFrequency": 0,
"slottable": true,
"timeFrom": 18,
"timeTo": 23,
"vastType": "fullscreen",
"allowAdsInVod": false
}
]
},
{
"channelTubeId": 58,
"name": "Kids Corner",
"url": "kids-corner",
"categoryName": "Kids",
"pictureUrl": null,
"description": null,
"order": 2,
"videos": [],
"vastSettings": []
}
]
}
/channels/{channelId}
Returns a single channel by numeric id, including videos and any configured platform-specific VAST ad settings.
Example response
{
"success": true,
"data": {
"channelTubeId": 42,
"name": "Main Channel",
"url": "main-channel",
"categoryName": "Entertainment",
"pictureUrl": "https://cdn.example.com/tubestrimm/123/channel.jpg",
"description": "My flagship channel.",
"order": 1,
"videos": [
{
"videoTubeId": 1001,
"title": "Intro to the Network",
"description": "A quick overview.",
"durationSeconds": 185.5,
"thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
"providerVideoId": "dQw4w9WgXcQ",
"providerName": "YouTube",
"categoryName": "Promo"
}
],
"vastSettings": [
{
"platform": "web",
"vastUrl": "https://ads.example.com/vast?channel=42&platform=web",
"vastVersion": 1,
"skippable": true,
"adFrequency": 1,
"midRollFrequency": 10,
"slottable": false,
"timeFrom": null,
"timeTo": null,
"vastType": "fullscreen",
"allowAdsInVod": false
}
]
}
}
VAST settings object
vastSettings is an array containing one entry per platform that has a VAST tag URL configured in the studio.
Platforms without ads configured are omitted, so an empty array means no platform-specific ads are set for the channel.
| Field | Type | Description |
|---|---|---|
platform | string | Target platform: web, roku, mobile, firetv, appletv, or androidtv. |
vastUrl | string | The VAST ad tag URL used for this platform. |
vastVersion | integer | Internal VAST configuration version. |
skippable | boolean | Whether ads can be skipped. |
adFrequency | integer | null | Pre-roll frequency (play an ad every N items). |
midRollFrequency | integer | null | Mid-roll frequency as a percentage interval; 0 disables mid-rolls. |
slottable | boolean | Whether ads are restricted to a daily time window. |
timeFrom | integer | null | Start hour (0–23) of the ad time window when slottable is true. |
timeTo | integer | null | End hour (0–23) of the ad time window when slottable is true. |
vastType | string | null | Ad presentation: fullscreen or picInPic. |
allowAdsInVod | boolean | When true, VAST ads may also run during VOD (on-demand) playback for this platform. |
Schedules
/channels/{channelId}/schedules?date=yyyy-MM-dd
Returns schedule blocks for a channel on the given date, including ordered videos with playback times.
Both regular scheduled videos and live streams linked to the channel are included. Each video has
isLive: false for regular schedule entries and
true for live streams. Live streams appear as single-video blocks sorted
with regular blocks by start time; their channelScheduleId is the negative
of the live video id.
Example request
GET /api/v1/rest/channels/42/schedules?date=2026-05-29
Authorization: Bearer {authToken}
Example response
{
"success": true,
"data": {
"channelTubeId": 42,
"date": "2026-05-29",
"schedules": [
{
"channelScheduleId": 901,
"startTime": "2026-05-29T06:00:00",
"published": true,
"loopDaily": false,
"videos": [
{
"videoTubeId": 1001,
"playbackOrderNumber": 1,
"title": "Morning Show",
"thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
"playTimeLabel": "06:00 AM - 06:30 AM",
"playbackStartTime": "2026-05-29T06:00:00",
"playbackEndTime": "2026-05-29T06:30:00",
"providerVideoId": "dQw4w9WgXcQ",
"providerName": "YouTube",
"isLive": false
},
{
"videoTubeId": 1002,
"playbackOrderNumber": 2,
"title": "Behind the Scenes",
"thumbnailUrl": "https://cdn.example.com/tubestrimm/123/thumb.jpg",
"playTimeLabel": "06:30 AM - 07:10 AM",
"playbackStartTime": "2026-05-29T06:30:00",
"playbackEndTime": "2026-05-29T07:10:00",
"providerVideoId": "abc123",
"providerName": "Custom",
"isLive": false
}
]
},
{
"channelScheduleId": -5501,
"startTime": "2026-05-29T14:00:00",
"published": true,
"loopDaily": false,
"videos": [
{
"videoTubeId": 5501,
"playbackOrderNumber": 1,
"title": "Live Town Hall",
"thumbnailUrl": "https://i.ytimg.com/vi/liveExample/hqdefault.jpg",
"playTimeLabel": "02:00 PM - 04:00 PM",
"playbackStartTime": "2026-05-29T14:00:00",
"playbackEndTime": "2026-05-29T16:00:00",
"providerVideoId": "liveExample",
"providerName": "YouTube",
"isLive": true
}
]
}
],
"totalVideos": 3,
"totalDurationLabel": "3h 10m"
}
}
Schedule times are returned in the channel's local timezone. When no blocks exist for the date,
schedules is an empty array and totalVideos is 0.
totalVideos and totalDurationLabel include both regular and live entries.
Favorites
Manage the authenticated user's favorite channels. Favorites are stored server-side and scoped to the
current user (the account identified by the Bearer token), so the same list is available across every device
and integration. All endpoints require the Authorization: Bearer {authToken} header.
/favorites
Lists the channels the current user has favorited, most recently favorited first.
Example request
GET /api/v1/rest/favorites
Authorization: Bearer {authToken}
Example response
{
"success": true,
"data": [
{
"channelTubeId": 42,
"name": "Main Channel",
"url": "main-channel",
"categoryName": "Entertainment",
"pictureUrl": "https://cdn.example.com/tubestrimm/123/channel.jpg",
"description": "My flagship channel.",
"favoritedAt": "2026-06-23T09:15:00Z"
},
{
"channelTubeId": 58,
"name": "Kids Corner",
"url": "kids-corner",
"categoryName": "Kids",
"pictureUrl": null,
"description": null,
"favoritedAt": "2026-06-20T18:02:11Z"
}
]
}
When the user has no favorites, data is an empty array.
/favorites/{channelId}
Adds a channel to the current user's favorites. The call is idempotent — favoriting a channel that is
already a favorite still returns success. Returns channel_not_found when the
channel id does not exist or has been deleted.
Example request
POST /api/v1/rest/favorites/42
Authorization: Bearer {authToken}
Example response
{
"success": true,
"data": {
"channelTubeId": 42,
"isFavorite": true
}
}
/favorites/{channelId}
Removes a channel from the current user's favorites. The call is idempotent — removing a channel that
is not a favorite still returns success. Returns channel_not_found when the
channel id does not exist or has been deleted.
Example request
DELETE /api/v1/rest/favorites/42
Authorization: Bearer {authToken}
Example response
{
"success": true,
"data": {
"channelTubeId": 42,
"isFavorite": false
}
}
REST API error codes
unauthorized— missing or invalid Bearer tokeninvalid_credentials— login failedaccount_locked— account is lockedaccount_not_activated— email not confirmedapp_not_found— no app configured for the platformchannel_not_found— channel id not found or not owned by userunsupported_platform— unknown app platform
Custom Services API (mobile)
Legacy-compatible API used by the Strimm mobile app template (api/v1/services/custom).
Responses wrap payloads in { data: ... } without a success flag.
Auth tokens are the same GUID Bearer tokens stored in strimm.AuthToken.
Base URL
https://newlook2.strimm.com/api/v1/services/custom
Response envelope
Successful responses:
{
"data": { ... }
}
Validation errors (HTTP 422):
{
"data": {
"message": "The given data was invalid.",
"errors": { ... }
}
}
Not found (HTTP 404):
{
"data": {
"message": "User is required",
"status_code": 404
}
}
Common headers
Authorization: Bearer {access_token}— required on protected auth routesPlatform-Id: ios/android— preferred client platform for app settings, store SKU selection, and entitlements (falls back toPlatform)Platform: mobile— scopes channel lists to the user's mobile app configurationDevice-Id— device id for subscription / VOD PPV entitlements (falls back toAccept-Platform-Device-Id)timezone— IANA or Windows timezone id for schedule-day filtering (e.g.America/New_York)Accept-Platform-Device-Id— legacy device id for password-unlock flows
Paid apps and VOD PPV may return HTTP 403 with
{ "data": { "message": "subscription_required", "status_code": 403 } }
on channel/schedule/VOD list endpoints when the viewer is not entitled.
Custom API — Authentication
/auth/login
No auth required. Accepts email (or username) and password.
{
"email": "creator@example.com",
"password": "your_password"
}
{
"data": {
"access_token": "00000000-0000-0000-0000-000000000000",
"token_type": "bearer",
"expires_in": 3600
}
}
/auth/refresh
Bearer required. Revokes the current token and returns a new one.
/auth/me
Bearer required.
{
"data": {
"id": 123,
"full_name": "Jane Creator",
"public_name": "creator",
"publicUrl": "creator",
"email": "creator@example.com"
}
}
/auth/logout
Bearer required. Revokes the token.
{
"data": { "message": "Success" }
}
Custom API — User & branding
Path parameter {id} is the account owner's numeric user id or publicUrl slug
(same value as the mobile app USER_ID env var).
/users/{id}/settings
White-label web/app branding from UserCustomApps, or mobile app colors when configured.
{
"data": {
"user_id": 123,
"title": "My Network",
"hex1": "#EF4E32",
"hex2": "#091221",
"hex3": "#102944",
"fontColor": "#EAE9F9",
"header_background": "white",
"FAQ": "...",
"PrivacyPolicy": "https://example.com/privacy",
"logo_header": "{base64}",
"logo_android": "{base64}",
"useVastSettings": false
}
}
/users/{id}/app_settings
Mobile (or Fire TV) app record from Studio → Apps. Send Platform-Id: ios or
android (or Platform: mobile) so store product IDs resolve for the correct store.
{
"data": {
"user_id": 123,
"slug": "my-network",
"app_name": "My Network App",
"hex1": "#FF5722",
"hex2": "#212121",
"hex3": "#000000",
"fontColor": "#FFFFFF",
"Logo": "{base64}",
"Icon": "{base64}",
"privacy_policy_link": "https://example.com/privacy",
"about": "Welcome.",
"platform": "Mobile",
"app_id": "7",
"is_paid": true,
"store_product_id": "com.yourbrand.app.weekly",
"store_products": [
{
"product_id": "com.yourbrand.app.weekly",
"billing_period": "Weekly",
"display_name": "Weekly access"
},
{
"product_id": "com.yourbrand.app.monthly",
"billing_period": "Monthly",
"display_name": "Monthly access"
},
{
"product_id": "com.yourbrand.app.yearly",
"billing_period": "Yearly",
"display_name": "Yearly access"
}
],
"vod_ppv_enabled": true,
"vod_ppv_store_product_id": "com.yourbrand.app.vod",
"vod_ppv_access_hours": 48
}
}
is_paid gates app-wide access via the subscription endpoints.
store_products lists every configured subscription for this client store;
store_product_id is the primary/first id (compat).
When vod_ppv_enabled is true, each VOD video requires a separate one-time purchase
(vod_ppv_store_product_id) that unlocks that video for vod_ppv_access_hours.
/users/{id}/categories?default=1
Channel categories for filters. Pass default=1 to omit nested channels.
/users/{id}/languages
Languages available for channel filtering.
Custom API — Channels & playback
/users/{id}/channels
Channels scheduled for today. Send Platform: mobile to limit to channels assigned in the mobile app.
Query params: language_id, category_id (comma-separated; 999 = live only),
search, skip, take, newest, oldest, most_subscribed.
GET /api/v1/services/custom/users/creator/channels?skip=0&take=20
Platform: mobile
timezone: America/New_York
{
"data": [
{
"id": 42,
"categoryId": 3,
"userId": 123,
"name": "Main Channel",
"url": "main-channel",
"pictureUrl": "https://cdn.example.com/.../channel.jpg",
"isWhiteLabeled": 1,
"playLiveFirst": false,
"privateChannel": false,
"isVerified": true,
"liveAvailable": true,
"guideMode": "fixed",
"keepGuideOpened": 0,
"vodAvailable": true,
"scheduleAvailable": true
}
]
}
vodAvailable is true when the channel has at least one linked VOD catalog video.
scheduleAvailable is true when the channel has a published linear schedule for today
(request timezone). Apps use these flags to show a VOD mode toggle and to keep VOD-only channels
in the list even when they have no schedule for today.
/users/{id}/channels/video
Scheduled videos for one or more channels and dates. Required query: channels_ids (comma-separated),
dates (yyyy-MM-dd, comma-separated). Optional: page, per_page, timezone.
GET /api/v1/services/custom/users/creator/channels/video?channels_ids=42,58&dates=2026-06-04&page=1&per_page=6
{
"data": [
{
"customId": "42-1001-1",
"videoTubeId": 1001,
"userId": 123,
"title": "Morning Show",
"providerVideoId": "dQw4w9WgXcQ",
"channelId": 42,
"duration": 1800,
"timeDuration": "0h. 30min",
"startDate": "2026-06-04 06:00:00",
"endDate": "2026-06-04 06:30:00",
"providerName": "YouTube",
"durationInDate": "6:00am-6:30am",
"thumbnail": "https://i.ytimg.com/vi/.../hqdefault.jpg",
"streamUrl": null,
"isVod": false
}
],
"links": { "first": null, "last": null, "prev": null, "next": null },
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 6,
"total": 1
}
}
Note: this endpoint returns the paginated object at the top level (data / links / meta),
not wrapped in an extra { data } envelope. isVod is always false for schedule rows.
/users/{id}/channels/vod
On-demand (VOD) catalog for one or more channels. Same paginated shape as
/users/{id}/channels/video. Required query: channels_ids (comma-separated).
Optional: page, per_page (default 50).
GET /api/v1/services/custom/users/creator/channels/vod?channels_ids=42&page=1&per_page=50
Platform-Id: ios
Device-Id: device-unique-id
{
"data": [
{
"customId": "42-2001-vod",
"videoTubeId": 2001,
"userId": 123,
"title": "Highlight Reel",
"providerVideoId": "987654321",
"channelId": 42,
"duration": 720,
"timeDuration": "0h. 12min",
"startDate": "2026-06-04 00:00:00",
"endDate": "2026-06-04 00:12:00",
"providerName": "Vimeo",
"durationInDate": "0:00-0:12",
"thumbnail": "https://cdn.example.com/.../thumb.jpg",
"streamUrl": "https://player.vimeo.com/...",
"isVod": true
}
],
"links": { "first": null, "last": null, "prev": null, "next": null },
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 50,
"total": 1
}
}
Apps should render timeDuration (not schedule start/end) when isVod is true.
When app VOD PPV is enabled, unlock each videoTubeId via the VOD PPV endpoints before playback.
/getChannelToken
Unlock a password-protected channel.
{
"channel_id": 42,
"password": "channel-secret"
}
With Accept-Platform-Device-Id, returns { "data": { "message": "Success" } }.
With Bearer auth only, returns a fresh token payload (same shape as login).
Custom API — Video tokens, live & favorites
/token_by_video/{videoTubeId}
Returns cached Vimeo progressive playback renditions for a video. Used by TV/app clients to pick the best width (1280 / 960 / 640 / 426) for direct playback. Non-expired renditions are returned when available; otherwise every cached rendition is returned so the client can still attempt playback.
GET /api/v1/services/custom/token_by_video/1001
{
"data": [
{
"url": "https://vod-progressive.akamaized.net/.../video-1280.mp4",
"expiration_date": "2026-06-08T18:30:00Z",
"width": "1280",
"height": "720"
},
{
"url": "https://vod-progressive.akamaized.net/.../video-640.mp4",
"expiration_date": "2026-06-08T18:30:00Z",
"width": "640",
"height": "360"
}
]
}
Returns { "data": [] } when no cached renditions exist for the video (e.g. non-Vimeo providers,
which are played directly via providerVideoId).
/users/{id}/channels/{channelId}/live?date=yyyy-MM-dd
Live-stream videos scheduled on a channel for the given day. When date is omitted the current
UTC date is used. Times are formatted yyyy-MM-dd HH:mm:ss.
GET /api/v1/services/custom/users/creator/channels/42/live?date=2026-06-08
{
"data": [
{
"videoTubeId": 5001,
"channelId": "42",
"startDate": "2026-06-08 19:00:00",
"endDate": "2026-06-08 20:00:00",
"description": "Live keynote",
"timeDuration": "1h. 0min",
"isPrivate": false,
"IsRRated": false,
"isRemovedByProvider": false,
"isRestrictedByProvider": false,
"providerVideoId": "987654321",
"thumbnail": "https://cdn.example.com/.../live.jpg",
"title": "Evening Live",
"uri": "",
"providerName": "Vimeo",
"live": true
}
]
}
/users/{id}/app/favorites
Lists the channels the user has favorited, most recently favorited first. Each item uses the same channel
shape as /users/{id}/channels with marked set to true.
GET /api/v1/services/custom/users/creator/app/favorites
{
"data": [
{
"id": 42,
"name": "Creator Channel",
"url": "creator-channel",
"pictureUrl": "https://cdn.example.com/.../channel.jpg",
"liveAvailable": true,
"marked": true
}
]
}
When the user has no favorites, data is an empty array.
/users/{id}/channels/{channelId}/app/favorite/add
/users/{id}/channels/{channelId}/app/favorite/remove
Adds or removes a channel from the user's favorites. The server validates that the channel exists and belongs to the account, persists the change server-side, then returns success (HTTP 200). Both calls are idempotent — re-adding an existing favorite or removing one that is not favorited still returns success.
{
"data": { "message": "Success" }
}
Returns 404 with { "data": { "message": "Channel not found", "status_code": 404 } }
when the channel is missing or not owned by the account.
/channels/{channelId}/vast?platform=mobile
Platform-specific VAST settings for a channel. Prefer Platform-Id header; optional
platform query overrides it. Response uses PascalCase keys for legacy TV clients.
{
"data": {
"ChannelId": 42,
"VastVersion": 1,
"VastUrl": "https://ads.example.com/vast?channel=42",
"Skippable": false,
"AdFrequency": 1,
"MidRollFrequency": 10,
"Slottable": false,
"TimeFrom": null,
"TimeTo": null,
"VastType": "fullscreen",
"Platform": "mobile",
"AllowAdsInVod": false
}
}
Custom API — Subscriptions & VOD PPV
Native store purchases for white-label apps configured in Studio → Apps.
Send Platform-Id (ios / android) and Device-Id on every call.
store_platform in request bodies is Apple or Google.
/users/{id}/apps/subscription/status
Whether the device/viewer is entitled to a paid app. When the app is not marked paid,
entitled is true and isPaidApp is false.
{
"data": {
"entitled": true,
"status": "active",
"expiresUtc": "2026-09-01T12:00:00Z",
"isPaidApp": true,
"storeProductId": "com.yourbrand.app.weekly",
"storeProductIds": [
"com.yourbrand.app.weekly",
"com.yourbrand.app.monthly",
"com.yourbrand.app.yearly"
]
}
}
/users/{id}/apps/subscription/verify
Verifies a store subscription receipt / purchase token and records entitlement for the device (and viewer when authenticated).
product_id must be one of the configured subscription Product IDs for that store
(any billing period).
{
"store_platform": "Apple",
"product_id": "com.yourbrand.app.monthly",
"receipt_data": "{transaction-receipt-or-purchase-token}",
"original_transaction_id": "1000000123456789",
"device_id": "device-unique-id"
}
{
"data": {
"ok": true,
"entitled": true,
"error": null,
"expiresUtc": "2026-09-01T12:00:00Z"
}
}
/users/{id}/apps/subscription/restore
Restores entitlement from known original transaction ids (and/or device history). Same result shape as verify.
{
"store_platform": "Apple",
"device_id": "device-unique-id",
"original_transaction_ids": ["1000000123456789"]
}
/users/{id}/apps/vod_ppv/status?video_tube_id={videoTubeId}
Per-video unlock status for app-level VOD pay-per-view. When VOD PPV is disabled for the app,
unlocked is true and vodPpvEnabled is false.
GET /api/v1/services/custom/users/creator/apps/vod_ppv/status?video_tube_id=2001
Platform-Id: ios
Device-Id: device-unique-id
{
"data": {
"vodPpvEnabled": true,
"unlocked": false,
"expiresUtc": null,
"storeProductId": "com.yourbrand.app.vod",
"accessDurationHours": 48
}
}
/users/{id}/apps/vod_ppv/verify
Verifies a one-time store purchase and unlocks a single video_tube_id for
accessDurationHours. Clients should finish the store transaction as consumable so the
same Product ID can unlock another video later.
{
"store_platform": "Google",
"product_id": "com.yourbrand.app.vod",
"receipt_data": "{purchase-token}",
"original_transaction_id": "GPA.1234-5678",
"device_id": "device-unique-id",
"video_tube_id": 2001
}
{
"data": {
"ok": true,
"unlocked": true,
"error": null,
"expiresUtc": "2026-06-06T18:00:00Z"
}
}
Validation failures return HTTP 422 with
{ "data": { "message": "The given data was invalid.", "errors": { "vod_ppv": "..." } } }.
Custom API — Analytics
Activity ingestion for the white-label TV and mobile apps. Replaces the retired
analytics-api.strimm.com service: apps report watch heartbeats and
login/logout events directly to this host.
/activity
No auth required. Accepts application/json or
application/x-www-form-urlencoded bodies. Also reachable at the
legacy-compatible path https://newlook2.strimm.com/api/v1/activity (same handler) for
clients that kept the old URL shape and only swap the host.
Request body
{
"source": "android_tv",
"action": "play_channel",
"client_id": "123",
"channel_id": "42",
"user_id": "device-id-or-viewer-id"
}
Fields
| Field | Type | Description |
|---|---|---|
source | string | Required. One of roku_app, fire_tv, android_tv, apple_tv, mobile_app_on_ios, mobile_app_on_android, custom_app_on_ios, custom_app_on_android, website_embedded_player, broadcast_on_strimm_dot_com. |
action | string | Required. play_channel, login, or logout (other legacy action names are accepted but not processed). |
client_id | integer | string | Strimm account owner user id (the app's USER_ID). |
user_id | string | End-viewer/device identifier (e.g. Android ID, identifierForVendor, Roku tracking id). Required for login/logout. |
channel_id | integer | string | Channel being played. Required for play_channel. |
payload | any | null | Optional extra data, stored as-is. |
Response (HTTP 200)
{
"message": "Success"
}
Note: for compatibility with the legacy analytics contract this endpoint returns a bare
{ "message" } object, not the { data } envelope used by the rest of the Custom API.
Watch-session heartbeats
While a channel is playing, post a play_channel event every 60 seconds.
The server folds consecutive heartbeats with the same
source + client_id + user_id + channel_id
into one watch session, extending its end time on each heartbeat. If no heartbeat arrives for more than
3 minutes the session is closed and its duration recorded (minimum 60 seconds credited); the next heartbeat
starts a new session.
Errors
403invalid_user— the owner ofchannel_idhas no qualifying subscription order422— validation failed (unknownsource/action, missing required field, or unparsable body)
Custom API notes
- Roku, Fire TV, and other platform-specific routes under
/api/v1/services/{platform}are planned separately. - Favorites (list/add/remove) are persisted server-side per user. Watch-later, search, and social auth endpoints are not yet implemented on this host.
-
Paid subscription and VOD PPV are configured per app in Studio → Apps. Subscription is app-wide;
VOD PPV unlocks are per
videoTubeId+ device (or authenticated viewer). -
Archive builds bake
IS_PAID,STORE_PRODUCT_ID_*,VOD_PPV_ENABLED,VOD_PPV_STORE_PRODUCT_ID_*, andVOD_PPV_ACCESS_HOURSinto the mobile template.env. - Configure the mobile app
API_BASE_URLto this site's origin (e.g.https://newlook2.strimm.com).
Legacy Web Services (ASMX-compatible)
Read-only compatibility endpoints that mirror the old *.asmx web services, kept for
shipped Roku / mobile / TV apps that still call the original URLs. Paths, parameters and response
bytes are identical to the legacy site — new integrations should use the REST API above instead.
Base URL
https://newlook2.strimm.com/WebServices
Conventions
- No authentication. Every endpoint accepts GET (query string) and POST (
application/x-www-form-urlencodedbody). - Except for
GetVastSettings(raw JSON body), responses are JSON wrapped in the classic ASMX XML envelope, served astext/xml; charset=utf-8:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">{ ...json... }</string>
- Every declared parameter must be present on the wire (an empty value counts); omitting one returns the legacy HTTP 500
Missing parameterplain-text page. - JSON keys are PascalCase and lookups that find no row serialize as the literal
null.
Legacy — VAST settings
/VastService.asmx/GetVastSettings?channelId={channelId}
VAST ad settings for a channel. Unlike the other legacy endpoints, the response is a raw JSON body
(no XML envelope, no Content-Type header). When the channel has per-platform rows configured,
the web row is returned.
Example response
{
"ChannelId": 42,
"VastVersion": 1,
"VastUrl": "https://ads.example.com/vast?channel=42",
"Skippable": false,
"AdFrequency": 1,
"MidRollFrequency": 10,
"Slottable": false,
"TimeFrom": null,
"TimeTo": null,
"VastType": "fullscreen",
"Platform": "web",
"AllowAdsInVod": false
}
Returns the literal null when the channel has no VAST settings.
Legacy — Roku app
/RokuAppGeneratorService.asmx/GetChannelTubeRokuSettings?channelId={channelId}
Whether a channel is included in the account's Roku app.
Example response (JSON inside the XML envelope)
{
"ChannelTubeId": 42,
"AddedToRoku": true,
"LastUpdateDate": "2024-01-22T12:56:28"
}
/RokuAppGeneratorService.asmx/GetUserRokuApp?userId={userId}
The account owner's Roku app record. Images are base64-encoded PNG bytes.
Example response (JSON inside the XML envelope)
{
"UserID": 123,
"AppName": "My Network",
"AdLink": "https://ads.example.com/roku",
"About": "Welcome to my channel network.",
"PrivacyPolicyLink": "https://example.com/privacy",
"ImageHD": "{base64}",
"ImageSD": "{base64}",
"ApiKey": "00000000-0000-0000-0000-000000000000"
}
Legacy — Mobile app
/MobileAppGeneratorService.asmx/GetChannelMobileApp?userId={userId}&channelId={channelId}
The account owner's mobile app branding plus the channel's app membership
(Sorting, AddedToApp, UseVastSettings come from the channel's
app assignment; they are null / account-level when the channel is not assigned).
Example response (JSON inside the XML envelope)
{
"UserID": 123,
"ChannelTubeId": 42,
"HeaderTitle": "My Network",
"Slug": "my-network",
"HeaderLogo": "{base64}",
"LogoIOS": "{base64}",
"LogoAndroid": null,
"Hex1": "FF5722",
"Hex2": "212121",
"Hex3": "000000",
"FontColor": "FFFFFF",
"About": "Welcome.",
"Sorting": 1,
"CopyrightLink": "",
"GDPRLink": "",
"CustomerSupportEmail": "support@example.com",
"FAQ": "",
"TermsLink": "",
"PrivacyPolicyLink": "https://example.com/privacy",
"Instagram": "",
"Facebook": "",
"Twitter": "",
"AddedToApp": true,
"UseVastSettings": false
}
When userId or channelId is sent empty, the envelope contains the plain string
One of the required fields is not passed.
Legacy — TV app
/TVAppGeneratorService.asmx/GetUserTVApp?userId={userId}&platform={platform}&skipImages={true|false}
The account owner's TV app (theme, images, and per-channel settings) for a platform:
fire-tv, android-tv, or apple-tv.
With skipImages=true the binary fields (Logo, Icon,
BackgroundImage, Image1, Image2) and AppId are returned as null.
Each entry in Settings includes the channel's VAST configuration when
UseVastSettings is enabled.
Example response (JSON inside the XML envelope)
{
"UserID": 123,
"AppName": "My Network TV",
"Slug": "my-network-tv",
"About": "Welcome.",
"PrivacyPolicyLink": "https://example.com/privacy",
"Logo": null,
"Icon": null,
"BackgroundImage": null,
"Image1": null,
"Image2": null,
"PrimaryColor": "FF5722",
"SecondaryColor": "212121",
"BackgroundColor": "000000",
"StyleColor": "102944",
"Platform": "fire-tv",
"ChannelId": null,
"AppId": null,
"Settings": [
{
"ChannelTubeId": 42,
"AddedToTV": true,
"Platform": "fire-tv",
"UseVastSettings": true,
"ChannelNumber": "1",
"AppId": null,
"LastUpdateDate": "2026-05-29T10:15:00",
"VastSettings": {
"ChannelId": 42,
"VastVersion": 1,
"VastUrl": "https://ads.example.com/vast?channel=42",
"Skippable": false,
"AdFrequency": 1,
"MidRollFrequency": 10,
"Slottable": false,
"TimeFrom": null,
"TimeTo": null,
"VastType": "fullscreen",
"Platform": "fire-tv",
"AllowAdsInVod": false
}
}
]
}
Errors (HTTP 200, JSON inside the XML envelope)
{"error":"One of the required fields is not passed"}—userIdorplatformsent empty{"error":"Application does not exist on {platform} platform"}— no app configured for the user on that platform