Skip to content

Chorki Mobile App — API Reference

Reverse-mapped from the Flutter app’s data layer (lib/data/datasources/** and lib/core/network/dio_api_provider.dart). This documents every network call the app makes.

Companion files in this folder:

  • chorki-api.postman_collection.json — import into Postman or Hoppscotch. Contains all requests, descriptions, and saved real responses.
  • chorki-api.postman_environment.json — variables (base URLs, token, country, language).
Variable Value Purpose
{{static_base}} https://api-static.chorki.com Catalog/content — GET, CDN-cached (7-day max-stale). Paths under /v1, /v2.
{{dynamic_base}} https://api-dynamic.chorki.com Auth + user data & writes. Paths under /v1, /v2, /v3.
{{ipinfo_base}} https://ipinfo.chorki.com/api/v2 Geo / VPN detection (sets country).
{{matomo_base}} https://analytics.chorki.com Matomo analytics (base from settings API).
{{frontend_base}} https://www.chorki.com Web frontend: captcha page + in-app WebViews.
{{video_cdn_base}} https://video.chorkicdn.com HLS playlists / segments.

Staging: the app uses api-static-porikkhamulok.chorki.net and api-dynamic-porikkhamulok.chorki.net (and the Turnstile test site key) when built with --dart-define=USE_STAGING=true; see lib/core/constant/api_url_const.dart.

Applied automatically by DioApiProvider to every backend call:

  • Query params: country=<code> and platform=mobile on all calls; GETs additionally send language=<en|bn>.
  • Headers: Accept: application/json, Content-Type: application/json, a ua_client_hints User-Agent, and Authorization: Bearer <token> when a user is logged in.
  • Timeouts: GET 20s · POST 30s · PUT/DELETE 60s.
  • Caching: static GETs use dio_cache_interceptor with 7-day max-stale (cache is bypassed on 401/403).
  1. Obtain a bearer token via one of the Auth flows (phone-OTP, email/password, or social). The token is returned as result.token.
  2. Set the token variable (collection or environment) to that value. All authenticated requests send it as Bearer {{token}}.
  3. Captcha: register, send-otp, and every login require a Cloudflare Turnstile captcha token from the {{frontend_base}}/captcha webview (siteKey 0x4AAAAAADILz4KWcCAtxCtt). It is short-lived and single-use.

64 requests across 19 groups. ✅ = a real production response is saved in the collection as an example.

App bootstrap: server-driven settings, geo/VPN detection, ads config. All public.

Method Path Auth Live Purpose
GET /v2/settings — ✅ Bootstrap configuration: navigation tabs, language config, min app versions, Matomo analyt…
GET (ipinfo) / — ✅ Returns caller’s country and proxy/VPN flags
GET /v1/ads — ✅ Ad units / AdMob configuration for free-tier playback

Phone-OTP, email/password, and social login flows on api-dynamic /v3 & /v2, plus session management. Login/register/OTP endpoints require a Cloudflare Turnstile captcha token.

Method Path Auth Live Purpose
POST /v3/auth/login — ⏳ Step 1 of phone login: sends an OTP SMS to the number
POST /v3/auth/login — ⏳ Step 2 of phone login: exchanges number+OTP for a bearer token (`result
POST /v3/auth/send-otp — ⏳ Sends an OTP to the given email (signup / verification flow)
POST /v3/auth/register — ⏳ Starts email signup; server emails an OTP which is then verified via /v2/auth/verify-otp a…
POST /v3/auth/login — ⏳ Email/password login, returns bearer token in `result
POST /v2/auth/verify-otp — ⏳ Verifies the OTP emailed during signup
POST /v2/auth/set-password — ⏳ Final step of email signup: sets the account password using the verified OTP
POST /v2/auth/check-email — ⏳ Tells the auth bottomsheet whether to show login (existing) or signup (new) for this email
POST /v1/auth/oauth/register — ⏳ Login/registration with a Google or Apple identity token
GET /v1/auth/user 🔒 ⏳ Current user profile incl
POST /v1/auth/user/vppa-consent 🔒 ⏳ Records the user’s acceptance of the VPPA (Video Privacy Protection Act) consent prompt
DELETE /v1/auth/device/authorizations 🔒 ⏳ Rejecting VPPA consent deletes the device authorization (device is signed out server-side)
POST /v1/auth/logout 🔒 ⏳ Invalidates the bearer token server-side; app then clears the cached user

Push-token registration and device/stream limit checks. Bearer auth.

Method Path Auth Live Purpose
POST /v1/auth/device/tokens 🔒 ⏳ Registers the FCM/APNs token so the backend can push notifications
GET /v1/auth/device/authorizations/usages 🔒 ⏳ How many devices are authorized vs
GET /v1/user/watch-history/active-stream 🔒 ⏳ Number of concurrent playback streams on the account (enforces stream limits before starti…

Server-driven tab pages (tab URIs come from the settings API) with cursor pagination.

Method Path Auth Live Purpose
GET /v2/:page_uri — ✅ Section-based page payload for a bottom-nav/header tab
GET /v2/movie — ✅ Concrete example of a tab page request (Movies tab)
GET /v2/ — ✅ Continuation request for infinite scroll

Content detail pages, adjacent-episode lookup, and the view counter.

Method Path Auth Live Purpose
GET /v1/:type/:slug — ✅ Full detail page for a content item: metadata, playback URL (HLS master playlist on the CD…
GET /v1/:type/:slug/adjacent — ✅ Previous/next episodes relative to the given content (used by the player’s next-episode lo…
POST /v1/analytics/views — ⏳ Increments the view counter when a content page is opened

Season and episode listings for series.

Method Path Auth Live Purpose
GET /v1/series/:slug/seasons — ✅ All seasons for a series
GET /v1/series/:slug/episodes — ✅ Episodes of one season, paginated

Full-text search (dynamic host), advanced-search meta types and meta lists.

Method Path Auth Live Purpose
GET /v1/search — ✅ Full-text content search with optional meta filters
GET /v2/settings/content-types — ✅ Meta types (genres, casts, …) used to build the advanced-search filter UI
GET /v1/metas/:slug — ✅ Lists metas of one type (e

Curated list pages (see-more targets).

Method Path Auth Live Purpose
GET /v1/lists/:slug — ✅ Curated collection page (‘see more’ targets from home sections)

Artist/meta profile pages and the artists archive with filters.

Method Path Auth Live Purpose
GET /v1/metas/:type/:slug — ✅ Artist/meta profile page with their content sections (route comes from content metas or th…
GET /v1/icons — ✅ Paginated artists archive
GET /v1/icons — ✅ Concrete example of the icons archive with type + search filters combined

Vertical short-video (bytes) feed.

Method Path Auth Live Purpose
GET /v1/suggestions/bytes — ✅ Vertical short-video feed

User playlists CRUD. Note: create and add-item share POST /v1/user/watchlists. Bearer auth.

Method Path Auth Live Purpose
GET /v1/user/watchlists 🔒 ⏳ All watchlist collections of the user, optionally with their items
POST /v1/user/watchlists 🔒 ⏳ Creates a new (empty) named watchlist
POST /v1/user/watchlists 🔒 ⏳ Same endpoint as create — sending playlist_id + playable_id/playable_type toggles th…
GET /v1/user/watchlists/:slug 🔒 ⏳ Items inside one watchlist
PUT /v1/user/watchlists/:id 🔒 ⏳ Renames a watchlist
DELETE /v1/user/watchlists/:id/remove-item 🔒 ⏳ Removes one item from a watchlist (DELETE with JSON body)
DELETE /v1/user/watchlists/:id 🔒 ⏳ Deletes the whole watchlist

Playback progress reporting, continue-watching, history search and removal. Bearer auth.

Method Path Auth Live Purpose
GET /v1/user/watch-history 🔒 ⏳ Full watch history of the active profile
POST /v1/user/watch-history 🔒 ⏳ Reports playback progress
POST /v1/user/watch-history/search 🔒 ⏳ Looks up history entries for a specific content
GET /v1/user/watch-history/continue-watching 🔒 ⏳ Continue-watching rail for the home screen
DELETE /v1/user/watch-history/:content_id 🔒 ⏳ Removes a single content from the history
DELETE /v1/user/watch-history 🔒 ⏳ ⚠️ Destructive: wipes the entire watch history of the active profile

Multi-profile support: list and switch (PIN for locked profiles). Bearer auth.

Method Path Auth Live Purpose
GET /v1/user/profiles 🔒 ⏳ All profiles on the account (multi-profile support incl
POST /v1/user/profiles/:id/switch 🔒 ⏳ Switches the active profile

Like/love/dislike reactions: batch check + toggle. Bearer auth.

Method Path Auth Live Purpose
POST /v1/user/content-reaction/check 🔒 ⏳ Returns the user’s existing reactions for a batch of contents (used on content pages and t…
POST /v1/user/content-reaction/react 🔒 ⏳ Creates/updates a reaction

SVOD packages and store receipt validation (Google Play / App Store).

Method Path Auth Live Purpose
GET /v1/packages — ✅ Available subscription plans (price, duration, features, store product ids)
POST /v1/payment/liap/validate/google_play 🔒 ⏳ Server-side receipt validation after a Google Play Billing purchase; activates the subscri…
POST /v1/payment/liap/validate/app_store 🔒 ⏳ Server-side receipt validation for Apple App Store purchases

TVOD purchases/rentals of the user. Bearer auth.

Method Path Auth Live Purpose
GET /v1/user/purchases/contents 🔒 ⏳ TVOD purchases/rentals of the user; paginated via `links

Server-driven popup notifications.

Method Path Auth Live Purpose
GET /v2/popup-notifications — ✅ Marketing/announcement popups shown on the home screen

Matomo media-analytics hits (tracker URL comes from settings).

Method Path Auth Live Purpose
GET (matomo) /matomo.php — ✅ Raw Matomo tracking endpoint

Everything else the app touches that is not the core REST API: captcha & payment WebViews, HLS CDN, local playback proxy, SDK-managed trackers.

Method Path Auth Live Purpose
GET (web) /captcha — ✅ HTML page hosting the Cloudflare Turnstile widget (siteKey 0x4AAAAAADILz4KWcCAtxCtt)
GET (award) /carnival — ✅ Promotional awards page opened in a WebView from the /awards deeplink
GET (web) /subscribe — · URL pattern for every in-app WebView that needs the user’s session: subscription checkout …
GET (cdn) /transcoded/:asset_id/playlist.m3u8 — ✅ Playback: content responses carry an HLS master-playlist URL on the video CDN
GET (local) /<downloaded-asset-path> — · Not a remote API: for offline playback the app runs an HTTP server on 127
GET (marktag) / — · Marktag SDK is initialized with tag host `mtag-cayk

Legend: 🔒 needs bearer token · ⏳ live capture pending a test token · · not executed (WebView/SDK/local).

Exact JSON shapes for POST/PUT/DELETE (from the app’s payload builders):

POST /v3/auth/login — Request OTP (phone)

{
"number": "+8801XXXXXXXXX",
"captcha": "<turnstile-token>"
}

POST /v3/auth/login — Login with phone + OTP

{
"number": "+8801XXXXXXXXX",
"otp": 1234,
"type": "android",
"deviceinfo": {
"brand": "samsung",
"device": "a52q",
"model": "SM-A525F",
"manufacturer": "samsung",
"product": "a52qnsxx",
"id": "TP1A.220624.014",
"isPhysicalDevice": true,
"version": {
"sdkInt": 34,
"release": "14",
"securityPatch": "2025-11-01"
}
},
"captcha": "<turnstile-token>"
}

POST /v3/auth/send-otp — Send OTP (email)

{
"email": "user@example.com",
"captcha": "<turnstile-token>"
}

POST /v3/auth/register — Register (email)

{
"email": "user@example.com",
"captcha": "<turnstile-token>"
}

POST /v3/auth/login — Login with email + password

{
"email": "user@example.com",
"password": "<password>",
"type": "android",
"captcha": "<turnstile-token>",
"deviceinfo": {
"brand": "samsung",
"device": "a52q",
"model": "SM-A525F",
"manufacturer": "samsung",
"product": "a52qnsxx",
"id": "TP1A.220624.014",
"isPhysicalDevice": true,
"version": {
"sdkInt": 34,
"release": "14",
"securityPatch": "2025-11-01"
}
}
}

POST /v2/auth/verify-otp — Verify email OTP

{
"email": "user@example.com",
"otp": "1234"
}

POST /v2/auth/set-password — Set password (email signup)

{
"password": "<new-password>",
"otp": "1234",
"email": "user@example.com"
}

POST /v2/auth/check-email — Check email exists

{
"email": "user@example.com"
}

POST /v1/auth/oauth/register — Social login (OAuth register)

{
"token": "<google-or-apple-id-token>",
"oauth_type": "google",
"type": "android",
"deviceinfo": {
"brand": "samsung",
"device": "a52q",
"model": "SM-A525F",
"manufacturer": "samsung",
"product": "a52qnsxx",
"id": "TP1A.220624.014",
"isPhysicalDevice": true,
"version": {
"sdkInt": 34,
"release": "14",
"securityPatch": "2025-11-01"
}
}
}

POST /v1/auth/device/tokens — Register push-notification device token

{
"device_token": "<fcm-token>",
"platform": "android",
"app_version": "2.1.1"
}

POST /v1/analytics/views — Record view count

{
"content_id": 227012874518691840,
"content_type": "App\\Models\\Video"
}

POST /v1/user/watchlists — Create watchlist

{
"title": "My favourites"
}

POST /v1/user/watchlists — Add content to watchlist

{
"playlist_id": "<watchlist-id>",
"playable_id": 227012874518691840,
"playable_type": "App\\Models\\Video"
}

PUT /v1/user/watchlists/:id — Rename watchlist

{
"title": "Renamed list"
}

DELETE /v1/user/watchlists/:id/remove-item — Remove item from watchlist

{
"playable_id": 227012874518691840,
"playable_type": "App\\Models\\Video"
}

POST /v1/user/watch-history — Add to watch history

{
"history": [
{
"content_id": 227012874518691840,
"content_type": "App\\Models\\Video",
"watched_duration": 120,
"watched_at": "2026-07-02T12:00:00.000+0600"
}
]
}

POST /v1/user/watch-history/search — Search watch history

{
"series_id": 203837912592957440
}

POST /v1/user/profiles/:id/switch — Switch active profile

{
"password": "<pin-if-locked>"
}

POST /v1/user/content-reaction/check — Check reactions on contents

{
"contents": [
{
"content_id": 227012874518691840,
"content_type": "App\\Models\\Video"
}
]
}

POST /v1/user/content-reaction/react — React to content

{
"content_id": 227012874518691840,
"content_type": "App\\Models\\Video",
"type": "like"
}

POST /v1/payment/liap/validate/google_play — Validate in-app purchase (Google Play)

{
"purchase_token": "<play-billing-purchase-token>",
"item_id": "<product-id>"
}

POST /v1/payment/liap/validate/app_store — Validate in-app purchase (App Store)

{
"receipt": "<base64-app-store-receipt>"
}
  • WebView checkout/account pages: the app takes a URL from the API (subscription.purchase_url, content.rental_url, tools/account URLs) and appends access_token=<token>&view=app_view. Payment gateways (bKash / SSLCommerz / etc.) run inside those pages; upi:// intents are handed to the OS.
  • HLS playback: content responses carry an HLS master-playlist URL on {{video_cdn_base}}; the player fetches master → variant → audio playlists and segments. DRM keys come from #EXT-X-KEY URIs. CDN auth tokens arrive in the settings response (obfuscated ytiruces block).
  • Offline playback: downloaded HLS is served by a loopback HTTP server on 127.0.0.1:8080 (lib/domain/services/local_server.dart) — not a remote endpoint.
  • SDK-managed: Marktag (mtag-cayk.chorki.com), Firebase (Analytics/Messaging/Remote Config), Sentry (crash ingest), and Chromecast (binary protobuf on device port 8009) have no directly-callable REST surface.

Endpoints were extracted by static analysis of the datasources and DioApiProvider. Public GETs were executed against production to capture real example responses; authenticated and write endpoints are fully documented and their live examples can be captured once a bearer token is set.