Pricing overrides
Every episode has a price at unlock time. That price is resolved through a strict cascade:
episode override → series override → market override → global default (30 coins)Higher in the cascade wins. All prices are expressed in coins (1 coin = $0.01 USD).
Where to edit
Section titled “Where to edit”Monetization → Pricing (/monetization/pricing) is the master surface. Three tabs:
- Default: read-only; shows the global 30-coin constant. Cannot be edited via UI (constant per
CONSTANTS.md). - Market overrides: per-country adjustments.
- Series/Episode overrides: per-title adjustments (edit from the series detail page too).
Adding a market override
Section titled “Adding a market override”Example: launch pricing in Egypt at 25 coins per episode.
- Pricing → Market overrides → New override
- Fill:
scope='market'scope_ref='EG'(ISO-2)coins=25currency_hint='EGP'(informational: the mobile app already knows the user’s currency)active_from(optional) /active_to(optional): leave blank for indefinite
- Save.
Every EG user will now see 25 coins per episode unless the series or episode has a more-specific override.
Adding a series override
Section titled “Adding a series override”From the Series detail → Pricing tab:
scope='series'scope_ref=<series_id>coins=<N>
A series-level override wins over market. Common use: premium-priced flagship shows.
Adding an episode override
Section titled “Adding an episode override”From the Episode editor:
scope='episode'scope_ref=<episode_id>coins=<N>
Wins over series and market. Common uses: finale episodes at a premium, special one-shot free episodes (coins=0, though the free-episode-count on the series usually covers this).
Time-boxed overrides
Section titled “Time-boxed overrides”active_from and active_to are ISO datetimes. A override with:
active_from=null, active_to=null→ indefiniteactive_from=2026-08-01, active_to=null→ starts on 2026-08-01, never expiresactive_from=null, active_to=2026-08-31→ active until end of Aug- both set → windowed
The resolver at unlock time filters by active_from ≤ now() ≤ active_to.
Resolution rules
Section titled “Resolution rules”- Look up all
price_overridesfor the target episode’s ID (scope=episode,scope_ref=episode_id, active window includes now). - If none, look up series overrides (
scope=series,scope_ref=episode.series_id). - If none, look up market override for the user’s country (
scope=market,scope_ref=user.country_code). - If none, use the global default (30 coins).
- The first hit wins: no averaging, no summing.
Where the resolver runs
Section titled “Where the resolver runs”PricingService.resolveForEpisode(episodeId, userCountry)in the API.- Called every time the mobile app hits
/v1/episodes/:id/unlock/quoteand/v1/episodes/:id/unlock. - Also read at admin catalog list time to show the effective price per episode in the panel.
Auditing
Section titled “Auditing”Every override create/update/delete writes an AuditLog entry with the full before/after JSON. Bulk price changes: use /v1/admin/pricing/overrides with the bulk endpoint (planned for launch): until then, individual writes.
Gotchas
Section titled “Gotchas”- The default 30 cannot be edited: it’s the constant. Change it globally would require a code change.
coins=0overrides: treated as “free” and skip the paywall. Use sparingly; usually the free-episode-count series field is a better lever.- Currency hint is informational. The mobile app knows the user’s currency from their locale.
currency_hintis only for admin UI display convenience. - Overrides don’t apply retroactively to unlocks already purchased. Only new unlocks feel the new price.
API calls
Section titled “API calls”| Action | Endpoint |
|---|---|
| Get pricing config | GET /v1/admin/pricing/config |
| Create override | POST /v1/admin/pricing/overrides |
| Update override | PUT /v1/admin/pricing/overrides/:id |
| Delete override | DELETE /v1/admin/pricing/overrides/:id |
Full details in API: Monetization.