Skip to content

API: Public endpoints affected by admin state

These are public / mobile-facing endpoints (not under /admin/*) whose behavior is determined by decisions made in the admin panel. They’re documented here because operators need to know exactly what they’re affecting.

Auth: none.

Returns feature flags whose key starts with public_. Non-public flags are stripped. Used by the mobile app at cold start.

{
"flags": {
"public_vas_enabled_eg": true,
"public_new_home_v2": { "enabled": true, "percentage": 25 }
}
}

Admin edits this via PUT /admin/flags: see Feature flags guide.

Auth: required (user JWT).

Query: market, lang, surface (default for_you).

Returns the composed feed for the user: rails, each with a resolved list of series. The composer reads:

  1. Active rails on the surface (from rails table).
  2. Each rail’s collection.
  3. If collection is manual: the collection_items list.
  4. If rule: the resolved query.
  5. Free-today series for the market (from free_series_rotations).
  6. Preview-reel entries (from series.editorial_hero_score).

Fallback: if the composer returns zero rails (e.g. curation empty in a new market), a hardcoded “newest published” collection is returned so the mobile app never renders empty.

Every rail includes an explanation string (non-null).

Auth: required.

Query: episodeId, limit.

Returns the first N visible comments for an episode (default 10). Used for the paywall-adjacent comment preview strip.

  • status='hidden' and status='deleted' comments are excluded.
  • Users with 3+ strikes have their new comments marked status='hidden' on creation (comment write endpoint, not this read).

Auth: required.

Redeems a promo code entered by the user.

{ "code": "WELCOME2026" }
  • Validates window, segment eligibility, per-user uses.
  • Mints coins (for coin_grant) or applies the effect (for bonus_multiplier on next purchase, trial_ext).
  • Increments promos.spent_coins.

Errors: promo_not_found, promo_expired, promo_budget_exhausted, promo_ineligible, promo_max_uses_reached.

Auth: required.

Returns the user’s derived balance and recent ledger.

  • Blocked with 403 if the user is suspended, banned, or deleted (see Suspend, ban, reactivate).
  • Otherwise returns { balanceTotal, balancePaid, balanceBonus, recentEntries: [...] }.

Auth: required.

Returns the resolved price for the episode given the user’s country. The resolver walks the pricing cascade episode → series → market → default.

Auth: required.

Spends coins to permanently unlock the episode. Writes double-entry ledger:

  • wallet_bonus (or wallet_paid) : -N (reason=‘unlock’)
  • sink_unlock : +N (reason=‘unlock’, ref_type=‘episode’, ref_id=episodeId)

Spend order: bonus first, then paid.

Auth: provider HMAC.

Provider webhooks (RevenueCat for IAP, card MID, dLocal, pawaPay). Each updates subscriptions + purchases rows and credits coins to the ledger. Admin visibility via transactions view.