Paywalls & experiments

Configure which products your paywall shows from the dashboard (no app release) and A/B test two layouts to see which converts. Your app asks for the current offering at runtime; EntitleHub decides what to return.

Offerings & packages

  • Offering: a named lineup you show on a paywall (e.g. default, black_friday). One is current.
  • Package: one purchasable option in an offering (e.g. monthly, annual, lifetime), pointing at a store product.

Create them in Dashboard → Paywalls. Because the app fetches the lineup at runtime, you can swap products, reorder, or launch a promo offering without shipping an update. The durable entitlement mapping still lives in the engine, a package just references a product by id.

Fetch the current offering

http
GET /v1/offerings/current?app_user_id=USER_ID
Authorization: Bearer pk_live_…

200 OK
{
  "identifier": "default",
  "display_name": "Default",
  "is_current": true,
  "packages": [
    { "identifier": "annual", "store": "app_store", "store_product_id": "pro_annual",
      "product": { "display_name": "Pro (Annual)", "type": "subscription",
                   "price_micros": 49990000, "currency": "USD", "entitlements": ["pro"] } }
  ]
}

Render a button per package (price/title come from the resolved product), then pass its store_product_id to your SDK's purchase(). GET /v1/offerings/all returns every offering. Returns 404 when no offering is configured.

Passing app_user_id

Include app_user_id so experiments can assign a variant (below). Without it you always get the plain current offering. The mobile SDKs pass it for you when you configure an app user.

A/B experiments

Start an experiment in Dashboard → Paywalls → Experiments: pick a control offering, a treatment offering, and the % of users routed to treatment. From then on, GET /v1/offerings/current?app_user_id=… returns the variant that user is assigned to, tagged so you can log exposure:

json
{
  "identifier": "black_friday",
  "packages": [ /* … */ ],
  "experiment": { "identifier": "price_test_q3", "variant": "treatment" }
}
  • Deterministic: a given app_user_id always lands in the same variant, across sessions and devices.
  • Conversion: measured per variant (share of exposed users who become entitled) on the experiment card.
  • One experiment runs per app at a time; stopping it keeps the results.
No SDK upgrade required

Experiments work through the same /v1/offerings/current call, if your app already fetches the current offering with an app_user_id, it's already experiment-ready.