Paywall management API
Read and edit paywall entitlements, SKU defaults and A/B experiments through GET and PUT /api/mobile/paywall, with every operation, field and error message.
/api/mobile/paywall is the management API the RevenueHog mobile app and the revenuehog-experiments skill use to edit paywall entitlements and experiments. The web dashboard enforces the same rules through the same code.
Auth is your session (cookie or Authorization: Bearer <session token>), rate limited to 120 requests per minute per user. An app outside your workspace returns 404 Unknown app.
Read state
/api/mobile/paywall?appId={appId}SessionReturns entitlements, experiments (with cheap per-variant assigned and exposed counts) and catalog, the mirror of the app's App Store Connect products. Add &experimentId=<id> for full results (see Experiments); that runs a bounded scan, so do not poll it.
Mutate
/api/mobile/paywallSessionThe body is a JSON object with appId and op. A successful mutation returns the refreshed overview plus catalog, and warnings when there are any (for example a product ID the catalog has not seen, which is a warning, not an error).
op | Fields |
|---|---|
upsertEntitlement | key, skus (ordered [{ productId, kind }], max 20) |
deleteEntitlement | key |
createExperiment | entitlement, name, durationDays, targetExposures?, variants ([{ key, weightPct, skus, isControl }]) |
updateExperiment | experimentId, plus any of entitlement, name, durationDays, targetExposures, variants, endsAt, weights ({ variantKey: pct }) |
refreshCatalog | none. Re-pulls products from App Store Connect. |
start, pause, resume, delete | experimentId |
conclude | experimentId, winnerKey, promote? |
{
"appId": "…", "op": "createExperiment",
"entitlement": "pro", "name": "Monthly first", "durationDays": 14,
"variants": [
{ "key": "control", "weightPct": 50, "isControl": true, "skus": [] },
{ "key": "monthly_first", "weightPct": 50, "isControl": false,
"skus": [{ "productId": "app_pro_monthly", "kind": "subscription" },
{ "productId": "app_pro_annual", "kind": "subscription" }] }
]
}Errors
Errors are { "error": "<sentence>" }, written to be shown to a person.
| Status | Error |
|---|---|
400 | Invalid JSON body, Body must be a JSON object, appId is required, experimentId is required |
400 | op must be one of upsertEntitlement, deleteEntitlement, createExperiment, updateExperiment, refreshCatalog, start, pause, resume, conclude, delete |
400 | Entitlement keys are short lowercase identifiers, like pro, skus must be an ordered list of { productId, kind }, Unknown entitlement, Unknown entitlement key |
400 | Name the experiment (at most 80 characters), Duration must be 1 to 180 days, Target exposures must be a whole count, variants must be a list of { key, weightPct, skus, isControl } |
400 | Variant rule sentences (see Experiments), endsAt must be a future date, weights must map every variant key to a percentage, Pick the winning variant |
401 | unauthorized |
404 | Unknown app, Unknown entitlement, Unknown experiment |
409 | This entitlement has experiments; history keeps it referenced |
409 | Only drafts start, Set a duration before starting, Set the entitlement's default SKUs before starting; the control variant snapshots them, An experiment is already live for this entitlement |
409 | Only running experiments pause, This experiment already ended, Only paused experiments resume, This experiment ended while paused; extend the end date first |
409 | Only live (or ended) experiments conclude, Only drafts delete, Completed experiments are immutable history |
409 | Only weights and the end date are editable while a test is live; changing what a variant shows mid-test corrupts its cohort |
409 | Catalog refresh failures, for example when the workspace has no App Store Connect credentials |
429 | rate_limited |
Related
Last updated on
Feedback API
Reference for POST /api/v1/feedback, the API key endpoint that forwards feedback from your servers and forms into RevenueHog, with every error and limit.
Revenue export API
Download your workspace's revenue lines as a streamed CSV from GET /api/export/revenue, filtered by date range and app, with columns and error responses.