What can I do with REST API v2?

REST API v2 follows RevenueCat's v2 paths, objects, list envelope and error format, so existing scripts keep working when you change the base URL and key. Authenticate with a secret key (Authorization: Bearer sk_...) or the dashboard session cookie. Lists return { "object": "list", "items": [...], "next_page": ..., "url": ... }; follow next_page to page. limit is 1 to 100 (default 20). RevenueDot-only endpoints are on Extensions.

Base URL: your server, for example http://localhost:8787 or https://revenuedot.example.com. The examples read REVENUEDOT_URL, PUBLIC_KEY, SECRET_KEY and PROJECT_ID from your shell.

Operations on this page (181)#

Projects#

Projects hold apps, the catalog, customers and webhooks.

List projects#

GET /v2/projects · Auth: secret key or dashboard session · Permissions: project_configuration:projects:read

A secret key sees its own project. A dashboard session sees every project the user is a member of.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Project.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.

Create a project#

POST /v2/projects · Auth: dashboard session · Permissions: project_configuration:projects:read_write

Needs a dashboard session: a secret key belongs to one project and cannot create another. The caller becomes the project's admin.

Request body (application/json)

Field Type Required Description
name string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects" \
  -H "Content-Type: application/json" -d '{"name":"Scanner"}'

Responses

  • 200: The project. Returns Project.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.

Apps#

One app per store, each with its public SDK key and store credentials.

List apps#

GET /v2/projects/{project_id}/apps · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of App.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create an app#

POST /v2/projects/{project_id}/apps · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read_write

One app per store. app_store and mac_app_store need bundle_id; play_store, amazon and galaxy need package_name. The app gets a public SDK key with the store's prefix (pdl_ for Paddle, roku_ for Roku, galx_ for the Galaxy Store). Other fields in the store object are saved as store credentials (for example subscription_private_key, subscription_key_id, subscription_key_issuer, play_service_account_credentials_json, Amazon's shared_secret, Stripe's stripe_secret_key and stripe_webhook_secret, Paddle's paddle_api_key and paddle_webhook_secret, Roku's roku_api_key, the Galaxy Store's galaxy_service_account_id, galaxy_service_account_private_key and galaxy_iap_public_key). Secrets are sealed and never returned. A Stripe publishable key (pk_…), a Paddle client-side token or a malformed signing secret is refused with 400. Store commission programs (RevenueDot extension, as RevenueCat's app settings): app_store.small_business_program and mac_app_store.small_business_program (Apple's Small Business Program, 15% instead of 30%) and amazon.small_business_accelerator (Amazon's Small Business Accelerator Program, 20% instead of 30%) take { "enrolled": true, "periods": [{ "entry_date": "2024-01-01", "exit_date": null }] }: up to 10 periods, YYYY-MM-DD, an exit date after its entry date, no overlaps; null removes the program. Proceeds in charts, metrics, exports and the REST API are recomputed for the dates; webhooks and integration events already sent keep their values. galaxy is a RevenueDot extension: RevenueCat's v2 API has no Galaxy app object.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
name string yes
type amazon, app_store, mac_app_store, play_store, stripe, rc_billing, roku, paddle, test_store, galaxy yes
app_store object no bundle_id plus optional credentials.
mac_app_store object no
play_store object no package_name plus optional credentials.
amazon object no
stripe object no
rc_billing object or null no
roku object or null no roku_api_key (sealed), roku_channel_id, roku_channel_name.
paddle object or null no paddle_api_key (sealed; pdl_live_apikey_… or pdl_sdbx_apikey_…), paddle_is_sandbox (only for keys made before May 2025), paddle_webhook_secret (sealed).
galaxy object no package_name plus galaxy_service_account_id, galaxy_service_account_private_key (sealed) and the optional galaxy_iap_public_key.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Scanner (iOS)","type":"app_store","app_store":{"bundle_id":"com.example.scanner"}}'

Responses

  • 201: The app. Returns App.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 201 response:

JSON
{
  "object": "app",
  "id": "appugfw01uy",
  "name": "Scanner (iOS)",
  "created_at": 1790801342594,
  "type": "app_store",
  "project_id": "proj18pzzkao",
  "custom_url_scheme": "rc-4d13549313",
  "app_store": {
    "bundle_id": "com.example.scanner",
    "app_store_connect_api_key_configured": false,
    "subscription_key_configured": false,
    "app_store_connect_vendor_number": null
  }
}

Get an app#

GET /v2/projects/{project_id}/apps/{app_id} · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The app. Returns App.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update an app and its store credentials#

POST /v2/projects/{project_id}/apps/{app_id} · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read_write

Send only the store object of the app's own type. A field set to null removes that credential; other values replace it. RevenueDot extensions in the store object: notification_forward_url (copy store notifications to another URL, for example RevenueCat during a dual run; null or "" turns it off), track_new_purchases, allow_unsigned_receipts, xcode_certificate, app_apple_id, pubsub_audience, pubsub_service_account; Amazon shared_secret, sns_topic_arn; Stripe stripe_secret_key, stripe_webhook_secret, stripe_account_id, app_user_id_source (metadata, customer_id, anonymous), app_user_id_metadata_key, register_on (invoice_paid, invoice_created); Paddle paddle_webhook_secret, app_user_id_source (custom_data, anonymous), app_user_id_custom_data_key; Galaxy Store galaxy_iap_public_key. See App Store setup, Google Play setup, Amazon Appstore setup, Stripe setup, Paddle setup, Roku setup and Galaxy Store setup.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Request body (application/json)

Field Type Required Description
name string no
app_store object no
mac_app_store object no
play_store object no
amazon object no
stripe object no
rc_billing object no
roku object no
paddle object no
galaxy object no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"app_store":{"subscription_private_key":"-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----","subscription_key_id":"ABC123DEFG","subscription_key_issuer":"57246542-96fe-1a63-e053-0824d011072a"}}'

Responses

  • 200: The app. Returns App.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete an app#

DELETE /v2/projects/{project_id}/apps/{app_id} · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read_write

Deletes the app and its products. Purchase history stays.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "app",
  "id": "…",
  "deleted_at": 1790801342625
}

Get an app's public SDK key#

GET /v2/projects/{project_id}/apps/{app_id}/public_api_keys · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID/public_api_keys" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: One key. Returns a list of PublicApiKey.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "public_api_key",
      "id": "pk_appvnrm0a5h",
      "key": "test_ea5120a23e7b9626f8eff225a627762c",
      "environment": "sandbox",
      "app_id": "appvnrm0a5h",
      "created_at": 1790800900758
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/apps/appvnrm0a5h/public_api_keys"
}

Get a StoreKit configuration file#

GET /v2/projects/{project_id}/apps/{app_id}/store_kit_config · Auth: secret key or dashboard session · Permissions: project_configuration:apps:read

A .storekit file for the products of an App Store app, to test purchases locally in Xcode. Prices come from the Test Store price when set, else 0.99.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID/store_kit_config" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The file contents.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Issue a subscriber access token#

POST /v2/projects/{project_id}/apps/{app_id}/authenticate · Auth: secret key or dashboard session · Permissions: iam:authorization:issue_token

A short-lived access token (one hour) for one app user id of one app. Send it as Authorization: Bearer rdat_... to the subscriber token endpoints (/v1/customer, /v1/customer/offerings ...), which answer for that app user id, or to any SDK endpoint for that app user id. It cannot be refreshed: ask for a new one. Only a hash of the token is stored.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Request body (application/json)

Field Type Required Description
app_user_id string yes The app user id the token speaks for.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID/authenticate" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"app_user_id":"user_1"}'

Responses

  • 200: The token.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "authentication",
  "access_token": "rdat_3f0c1d0b9e8a7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c8b7a6f5e4d3c2b",
  "expires_at": 1790804514034
}

List the products in the app's store#

GET /v2/projects/{project_id}/apps/{app_id}/store_products · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:products:read

What the app's store has, read with the credentials the app already has, every page of the store's lists, each item marked in_catalog. Nothing in the store changes. See Import products.

  • App Store and Mac App Store: the App Store Connect API key (app_store_connect_api_key, _id, _issuer), a team key with the App Manager role. Subscriptions by subscription group, then in-app purchases (consumable, non-consumable, non-renewing).
  • Google Play: the service account, with "View app information and download bulk reports (read-only)" in Play Console. One item per subscription base plan (subscription_id:base_plan_id) with its billing period, then one-time products (monetization.onetimeproducts, or the legacy inappproducts list where that API is not available).
  • Stripe: the app's restricted key with "Products" read (it covers prices). One item per active price; recurring prices are subscriptions.

422 unprocessable_entity_error when the credential is missing or the store refuses it (the message names the role or permission), for Amazon (it has no API that lists in-app items; add products by SKU) and the Test Store. 422 store_error with retryable: true while the store cannot be reached.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID/store_products" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The store's products. next_page is always null: every store page has been read.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/apps/app1a2b3c4d/store_products",
  "app_id": "app1a2b3c4d",
  "store": "app_store",
  "warnings": [],
  "items": [
    {
      "object": "store_product_listing",
      "store_identifier": "pro_monthly",
      "type": "subscription",
      "display_name": "Pro Monthly",
      "duration": "P1M",
      "store_state": "APPROVED",
      "group": {
        "id": "21000001",
        "name": "Pro"
      },
      "price": null,
      "importable": true,
      "note": null,
      "in_catalog": true,
      "product_id": "prod1a2b3c4d5e"
    },
    {
      "object": "store_product_listing",
      "store_identifier": "pro_annual",
      "type": "subscription",
      "display_name": "Pro Annual",
      "duration": "P1Y",
      "store_state": "APPROVED",
      "group": {
        "id": "21000001",
        "name": "Pro"
      },
      "price": null,
      "importable": true,
      "note": null,
      "in_catalog": false,
      "product_id": null
    },
    {
      "object": "store_product_listing",
      "store_identifier": "coins_100",
      "type": "consumable",
      "display_name": "100 coins",
      "duration": null,
      "store_state": "APPROVED",
      "group": null,
      "price": null,
      "importable": true,
      "note": null,
      "in_catalog": false,
      "product_id": null
    }
  ]
}

Import products from the app's store#

POST /v2/projects/{project_id}/apps/{app_id}/store_products/actions/import · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:products:read_write

Creates catalog products for the chosen store identifiers. The store is read again, so the type, duration and display name always come from the store. Products already in the catalog are left as they are and reported in existing; identifiers the store does not have, or cannot be imported, are reported in failed. Every created and existing product is attached to the entitlement_ids. With entitlement_ids, an API key also needs project_configuration:entitlements:read_write. Running the same import twice changes nothing. Flat-rate Stripe prices also become web products, so the web checkout can sell them.

201 when at least one product was created, else 200. Errors as for listing; 400 for an entitlement_ids entry that is not an entitlement of the project.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
app_id string yes App id (app...).

Request body (application/json)

Field Type Required Description
store_identifiers array of string yes store_identifier values from the list.
entitlement_ids array of string no Entitlements to attach the products to. Optional.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/apps/$APP_ID/store_products/actions/import" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"store_identifiers":["pro_annual","coins_100"],"entitlement_ids":["entl1a2b3c4d5e"]}'

Responses

  • 200: Nothing new was created. Returns StoreProductImport.
  • 201: Products were created. Returns StoreProductImport.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Products#

Store products.

List products#

GET /v2/projects/{project_id}/products · Auth: secret key or dashboard session · Permissions: project_configuration:products:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
app_id string no Only this app's products.
expand array of items.app, items.indicative_price, items.store_details no items.app embeds each product's app. items.indicative_price adds each product's indicative price: the Test Store price, else the store price from the last price read (United States first), else the Stripe web product's price. items.store_details (RevenueDot extension) adds each product's store status and price; see store prices.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Product.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a product#

POST /v2/projects/{project_id}/products · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

store_identifier is the store's product id. For Google Play subscriptions use subscriptionId:basePlanId; for an App Store monthly billing plan with a 12-month commitment (iOS 26.4) use productId:monthly. Set subscription.duration (ISO 8601, for example P1M): the Test Store uses it as the period, and MRR uses it for every store. test_store_price sets what the SDK shows for a Test Store product.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
expand array of indicative_price, store_details no indicative_price adds RevenueCat's IndicativePrice: the Test Store price; else the App Store or Google Play price in the United States from the last store price read (or the in-app purchase's base territory, or the first territory with a price); else the Stripe web product's price; null when none is known. store_details (RevenueDot extension) adds the store's status, base price, number of priced territories and when they were read.

Request body (application/json)

Field Type Required Description
store_identifier string yes
app_id string yes
type subscription, one_time, consumable, non_consumable, non_renewing_subscription yes
display_name string or null no
title string or null no Alias of display_name.
price_identifier string or null no Accepted and ignored.
subscription object or null no
subscription.duration string or null no ISO 8601 period such as P1W, P1M, P1Y or P3D.
test_store_price object or null no RevenueDot extension. The default Test Store price (Test Store products only): it adds or updates the price in this currency and keeps the other currencies. Null clears every price. Read it back with expand=indicative_price; list every currency with GET …/prices.
test_store_price.amount_micros integer yes Price in micros: 9.99 is 9990000.
test_store_price.currency string yes ISO 4217 code such as USD or EUR. A code with no exchange rate to USD is refused (its purchases would record no revenue).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"store_identifier":"pro_monthly","app_id":"appvnrm0a5h","type":"subscription","display_name":"Pro monthly","subscription":{"duration":"P1M"}}'

Responses

  • 201: The product. Returns Product.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 201 response:

JSON
{
  "object": "product",
  "id": "prode0zhpfisko",
  "store_identifier": "pro_monthly",
  "type": "subscription",
  "state": "active",
  "subscription": {
    "duration": "P1M",
    "grace_period_duration": null,
    "trial_duration": null
  },
  "created_at": 1790800900948,
  "app_id": "appvnrm0a5h",
  "display_name": "Pro monthly"
}

Get a product#

GET /v2/projects/{project_id}/products/{product_id} · Auth: secret key or dashboard session · Permissions: project_configuration:products:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id (prod...).

Query parameters

Name Type Required Description
expand array of app, indicative_price, store_details no app embeds the app. indicative_price adds RevenueCat's IndicativePrice: the Test Store price; else the App Store or Google Play price in the United States from the last store price read (or the in-app purchase's base territory, or the first territory with a price); else the Stripe web product's price; null when none is known. store_details (RevenueDot extension) adds the store's status, base price, number of priced territories and when they were read.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The product. Returns Product.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "product",
  "id": "prode0zhpfisko",
  "store_identifier": "pro_monthly",
  "type": "subscription",
  "state": "active",
  "subscription": {
    "duration": "P1M",
    "grace_period_duration": null,
    "trial_duration": null
  },
  "created_at": 1790800900948,
  "app_id": "appvnrm0a5h",
  "display_name": "Pro monthly"
}

Update a product#

POST /v2/projects/{project_id}/products/{product_id} · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

RevenueDot also lets you correct type and subscription.duration (null clears it), and set or clear test_store_price.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Query parameters

Name Type Required Description
expand array of app, indicative_price, store_details no indicative_price adds RevenueCat's IndicativePrice: the Test Store price; else the App Store or Google Play price in the United States from the last store price read (or the in-app purchase's base territory, or the first territory with a price); else the Stripe web product's price; null when none is known. store_details (RevenueDot extension) adds the store's status, base price, number of priced territories and when they were read.

Request body (application/json)

Field Type Required Description
display_name string no
type subscription, one_time, consumable, non_consumable, non_renewing_subscription no
subscription object no
subscription.duration string or null no
test_store_price object or null no RevenueDot extension. The default Test Store price (Test Store products only): it adds or updates the price in this currency and keeps the other currencies. Null clears every price. Read it back with expand=indicative_price; list every currency with GET …/prices.
test_store_price.amount_micros integer yes Price in micros: 9.99 is 9990000.
test_store_price.currency string yes ISO 4217 code such as USD or EUR. A code with no exchange rate to USD is refused (its purchases would record no revenue).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"display_name":"Pro (monthly)","test_store_price":{"amount_micros":9990000,"currency":"USD"}}'

Responses

  • 200: The product. Returns Product.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete a product#

DELETE /v2/projects/{project_id}/products/{product_id} · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

Detaches it from entitlements and packages. Purchase history keeps the store id.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "product",
  "id": "…",
  "deleted_at": 1790801342625
}

List a product's prices#

GET /v2/projects/{project_id}/products/{product_id}/prices · Auth: secret key or dashboard session · Permissions: project_configuration:products:read

Every price of a Test Store product, one per currency, the default first (the default is what indicative_price shows and what a customer whose currency has no price sees). For a Stripe web product, its Stripe price (id is the Stripe price id). Other products answer 400. The answer is a JSON array, not a list object, as in RevenueCat.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/prices" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The prices.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
[
  {
    "id": "prcx8k2m4q9w1z7d",
    "currency": "USD",
    "amount_micros": 9990000
  },
  {
    "id": "prc3n6p0r8t2v4b5",
    "currency": "EUR",
    "amount_micros": 8990000
  }
]

List a product's prices (old path)#

GET /v2/projects/{project_id}/products/{product_id}/test_store_prices · Auth: secret key or dashboard session · Permissions: project_configuration:products:read

The same as GET …/prices. Deprecated in RevenueCat; use …/prices.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/test_store_prices" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The prices.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Add Test Store prices#

POST /v2/projects/{project_id}/products/{product_id}/test_store_prices · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

Adds a price in each currency (Test Store products only; other products answer 400). Each currency once per request. A currency the product already has gets the new amount. A product without a price gets USD as its default when USD is among them, else the first one. The SDK shows each customer the price in their storefront's currency, else the default. Answers the prices it wrote, as an array.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Request body (application/json)

Field Type Required Description
prices array of object yes
prices[].currency string yes ISO 4217 code such as EUR. A code with no exchange rate to USD is refused.
prices[].amount_micros integer yes Price in micros: 8.99 is 8990000.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/test_store_prices" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"prices":[{"currency":"EUR","amount_micros":8990000},{"currency":"GBP","amount_micros":7990000}]}'

Responses

  • 201: The prices written.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 201 response:

JSON
[
  {
    "id": "prc3n6p0r8t2v4b5",
    "currency": "EUR",
    "amount_micros": 8990000
  },
  {
    "id": "prc9d1f3h5j7l2c4",
    "currency": "GBP",
    "amount_micros": 7990000
  }
]

Change a Test Store price#

PATCH /v2/projects/{project_id}/products/{product_id}/prices/{currency} · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

Sets the amount of the product's price in this currency. 404 when the product has no price in it (add one with POST …/test_store_prices).

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.
currency string yes ISO 4217 code of the price, such as EUR.

Request body (application/json)

Field Type Required Description
amount_micros integer yes Price in micros.

Example request

Shell
curl -s -X PATCH "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/prices/$CURRENCY" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"amount_micros":9490000}'

Responses

  • 200: The price. Returns ProductPrice.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "id": "prc3n6p0r8t2v4b5",
  "currency": "EUR",
  "amount_micros": 9490000
}

Remove a Test Store price#

DELETE /v2/projects/{project_id}/products/{product_id}/prices/{currency} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:products:read_write

RevenueDot extension (RevenueCat has no way to remove a currency). Removing the default price makes USD, else the first remaining currency, the default; removing the last price leaves the product without one.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.
currency string yes ISO 4217 code of the price.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/prices/$CURRENCY" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Removed.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "product_price",
  "id": "prcx8k2m4n7q1z",
  "currency": "GBP",
  "deleted_at": 1790801342625
}

Archive a product#

POST /v2/projects/{project_id}/products/{product_id}/actions/archive · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/actions/archive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The archived product. Returns Product.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Unarchive a product#

POST /v2/projects/{project_id}/products/{product_id}/actions/unarchive · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/actions/unarchive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The product. Returns Product.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create the product in its store#

POST /v2/projects/{project_id}/products/{product_id}/create_in_store · Auth: secret key or dashboard session · Permissions: project_configuration:products:read_write

Creates a catalog product in the store its app belongs to. The product's display name becomes the store name.

  • App Store (needs the app's App Store Connect API key with the App Manager role: app_store_connect_api_key, app_store_connect_api_key_id, app_store_connect_api_key_issuer). A subscription needs store_information with duration and subscription_group_name (or subscription_group_id); the group is reused by name or created. Consumables, non-consumables and non-renewing subscriptions need no body. Add prices, a review screenshot and localizations in App Store Connect before submitting.
  • Google Play (a RevenueDot addition; needs the service account with "Manage store presence"): a subscription with one listing in the app's default language. Add its base plans and prices in Play Console. One-time products answer 422, because Google needs a price to create them.

409 when the store already has the product id, 422 without the credentials or for another store, 422 store_error with retryable: true while the store is down.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
product_id string yes Product id (prod...).

Request body (application/json)

Field Type Required Description
store_information object or object no App Store subscriptions only.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/products/$PRODUCT_ID/create_in_store" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"store_information":{"duration":"ONE_MONTH","subscription_group_name":"Pro"}}'

Responses

  • 201: The product in the store.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 201 response:

JSON
{
  "created_product": {
    "object": "store_product",
    "id": "6743920115",
    "name": "Pro Monthly",
    "product_identifier": "pro_monthly"
  }
}

Entitlements#

The access your app checks, unlocked by products.

List entitlements#

GET /v2/projects/{project_id}/entitlements · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
expand array of items.product no items.product embeds the attached products.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Entitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create an entitlement#

POST /v2/projects/{project_id}/entitlements · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
lookup_key string yes What apps check, for example pro.
display_name string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"lookup_key":"pro","display_name":"Pro access"}'

Responses

  • 201: The entitlement. Returns Entitlement.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 201 response:

JSON
{
  "object": "entitlement",
  "id": "entl1v0bp6r0qs",
  "project_id": "proj18pzzkao",
  "lookup_key": "pro",
  "display_name": "Pro access",
  "created_at": 1790800901115,
  "state": "active"
}

Get an entitlement#

GET /v2/projects/{project_id}/entitlements/{entitlement_id} · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id (entl...).

Query parameters

Name Type Required Description
expand array of product no product embeds the attached products.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The entitlement. Returns Entitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "entitlement",
  "id": "entl1v0bp6r0qs",
  "project_id": "proj18pzzkao",
  "lookup_key": "pro",
  "display_name": "Pro access",
  "created_at": 1790800901115,
  "state": "active"
}

Rename an entitlement#

POST /v2/projects/{project_id}/entitlements/{entitlement_id} · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Request body (application/json)

Field Type Required Description
display_name string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The entitlement. Returns Entitlement.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete an entitlement#

DELETE /v2/projects/{project_id}/entitlements/{entitlement_id} · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "entitlement",
  "id": "…",
  "deleted_at": 1790801342625
}

Archive an entitlement#

POST /v2/projects/{project_id}/entitlements/{entitlement_id}/actions/archive · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID/actions/archive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The archived entitlement. Returns Entitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Unarchive an entitlement#

POST /v2/projects/{project_id}/entitlements/{entitlement_id}/actions/unarchive · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID/actions/unarchive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The entitlement. Returns Entitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List an entitlement's products#

GET /v2/projects/{project_id}/entitlements/{entitlement_id}/products · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID/products" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Product.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Attach products to an entitlement#

POST /v2/projects/{project_id}/entitlements/{entitlement_id}/actions/attach_products · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Any of these products unlocks the entitlement. Every id must belong to the project, or nothing changes.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Request body (application/json)

Field Type Required Description
product_ids array of string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID/actions/attach_products" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"product_ids":["prode0zhpfisko","prodz2c0dt6z9x"]}'

Responses

  • 200: The entitlement with its products. Returns Entitlement.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Detach products from an entitlement#

POST /v2/projects/{project_id}/entitlements/{entitlement_id}/actions/detach_products · Auth: secret key or dashboard session · Permissions: project_configuration:entitlements:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
entitlement_id string yes Entitlement id.

Request body (application/json)

Field Type Required Description
product_ids array of string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/entitlements/$ENTITLEMENT_ID/actions/detach_products" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The entitlement with its products. Returns Entitlement.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Offerings#

Groups of packages the paywall shows.

List offerings#

GET /v2/projects/{project_id}/offerings · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
expand array of items.package, items.package.product no Embed packages, and their products.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Offering.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create an offering#

POST /v2/projects/{project_id}/offerings · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

The project's first offering becomes current.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
lookup_key string yes
display_name string yes
metadata object or null no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"lookup_key":"default","display_name":"Standard plans"}'

Responses

  • 201: The offering. Returns Offering.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Get an offering#

GET /v2/projects/{project_id}/offerings/{offering_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id (ofrng...).

Query parameters

Name Type Required Description
expand array of package, package.product no Embed packages, and their products.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The offering. Returns Offering.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update an offering or make it current#

POST /v2/projects/{project_id}/offerings/{offering_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

is_current: true makes it the only current offering. An archived offering cannot be made current (422).

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id.

Request body (application/json)

Field Type Required Description
display_name string no
is_current boolean no
metadata object or null no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"is_current":true}'

Responses

  • 200: The offering. Returns Offering.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Delete an offering#

DELETE /v2/projects/{project_id}/offerings/{offering_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Deletes its packages and clears customer overrides that point to it. An offering that a draft, running or paused experiment uses (as a variant's offering or a placement offering) answers 409 and names the experiment: stop the experiment or pick another offering in it first. A stopped experiment keeps its results and shows the deleted offering's id.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 200 response:

JSON
{
  "object": "offering",
  "id": "…",
  "deleted_at": 1790801342625
}

Duplicate an offering#

POST /v2/projects/{project_id}/offerings/{offering_id}/actions/duplicate · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Copies an offering with its packages, for an experiment's treatment. The copy is never current. Without packages the copy is exact: every package in order, with the same products. With packages, the list sets which packages are copied and in what order, and a package's products replaces its products (to test another price, period, trial or introductory offer). copy_paywall copies the offering's paywall, draft and published content, onto the copy.

Answers 400 when a source_package_id is not a package of this offering or repeats, a product is not in the project or repeats in a package, or copy_paywall is true and the offering has no paywall. Answers 409 when the lookup_key is taken, or two products of the same app in a package have overlapping eligibility_criteria.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes The offering to copy.

Request body (application/json)

Field Type Required Description
lookup_key string yes
display_name string yes
metadata object or null no Default: the source offering's metadata.
packages array of object no Packages to copy, in the new order. Omitted: every package, as it is.
packages[].source_package_id string yes A package of the source offering (pkge...).
packages[].products array of object no Replaces the package's products. Omitted: the source package's products.
packages[].products[].product_id string yes
packages[].products[].eligibility_criteria all, google_sdk_lt_6, google_sdk_ge_6 yes
copy_paywall boolean no Also copy the offering's paywall onto the copy.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID/actions/duplicate" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"lookup_key":"default_price","display_name":"Standard plans (price point)","packages":[{"source_package_id":"pkge1a2b3c4d5e","products":[{"product_id":"prod9k8j7h6g5f","eligibility_criteria":"all"}]},{"source_package_id":"pkge6f7g8h9i0j"}]}'

Responses

  • 201: The copy, with its packages and their products expanded. Returns Offering.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Archive an offering#

POST /v2/projects/{project_id}/offerings/{offering_id}/actions/archive · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

An offering that a draft, running or paused experiment uses cannot be archived (409); the current offering cannot be archived (422).

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID/actions/archive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The archived offering. Returns Offering.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Unarchive an offering#

POST /v2/projects/{project_id}/offerings/{offering_id}/actions/unarchive · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id.

Request body (application/json)

Field Type Required Description
unarchive_referenced_entities boolean no Also unarchive the products in its packages.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID/actions/unarchive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The offering. Returns Offering.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Packages#

One choice on the paywall, with one product per app.

List an offering's packages#

GET /v2/projects/{project_id}/offerings/{offering_id}/packages · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read

Ordered by position, then creation: the order the SDK shows them in.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id.

Query parameters

Name Type Required Description
expand array of items.product no Embed products.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID/packages" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Package.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a package#

POST /v2/projects/{project_id}/offerings/{offering_id}/packages · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read_write

Use the standard lookup keys ($rc_monthly, $rc_annual, $rc_weekly, $rc_lifetime ...) so the SDK's convenience accessors work. Without position, the package goes last.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
offering_id string yes Offering id.

Request body (application/json)

Field Type Required Description
lookup_key string yes
display_name string yes
position integer no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/offerings/$OFFERING_ID/packages" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"lookup_key":"$rc_monthly","display_name":"Monthly","position":0}'

Responses

  • 201: The package. Returns Package.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Get a package#

GET /v2/projects/{project_id}/packages/{package_id} · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
package_id string yes Package id (pkge...).

Query parameters

Name Type Required Description
expand array of product no Embed products.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/packages/$PACKAGE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The package. Returns Package.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update a package#

POST /v2/projects/{project_id}/packages/{package_id} · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
package_id string yes Package id.

Request body (application/json)

Field Type Required Description
display_name string no
position integer no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/packages/$PACKAGE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The package. Returns Package.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete a package#

DELETE /v2/projects/{project_id}/packages/{package_id} · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
package_id string yes Package id.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/packages/$PACKAGE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "package",
  "id": "…",
  "deleted_at": 1790801342625
}

List a package's products#

GET /v2/projects/{project_id}/packages/{package_id}/products · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
package_id string yes Package id.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/packages/$PACKAGE_ID/products" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of PackageProduct.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Attach products to a package#

POST /v2/projects/{project_id}/packages/{package_id}/actions/attach_products · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read_write

One product per app, so each app's SDK finds its product. Two products of the same app can share a package only with non-overlapping eligibility_criteria (409 otherwise).

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
package_id string yes Package id.

Request body (application/json)

Field Type Required Description
products array of object yes
products[].product_id string yes
products[].eligibility_criteria all, google_sdk_lt_6, google_sdk_ge_6 yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/packages/$PACKAGE_ID/actions/attach_products" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"products":[{"product_id":"prode0zhpfisko","eligibility_criteria":"all"}]}'

Responses

  • 200: The package with its products. Returns Package.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Detach products from a package#

POST /v2/projects/{project_id}/packages/{package_id}/actions/detach_products · Auth: secret key or dashboard session · Permissions: project_configuration:packages:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
package_id string yes Package id.

Request body (application/json)

Field Type Required Description
product_ids array of string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/packages/$PACKAGE_ID/actions/detach_products" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The package with its products. Returns Package.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Customers#

Customers, their attributes, entitlements, subscriptions, purchases and events.

List or search customers#

GET /v2/projects/{project_id}/customers · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Newest first (by first seen).

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
search string no Exact match on an app user id, the $email attribute (any case) or a store transaction id.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Customer.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a customer#

POST /v2/projects/{project_id}/customers · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
id string yes App user id.
attributes array of object no
attributes[].name string yes
attributes[].value string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"id":"user_42","attributes":[{"name":"$email","value":"ana@example.com"}]}'

Responses

  • 201: The customer. Returns Customer.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Get a customer#

GET /v2/projects/{project_id}/customers/{customer_id} · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
expand array of attributes no attributes embeds the customer's attributes.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The customer. Returns Customer.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "customer",
  "id": "user_1",
  "project_id": "proj18pzzkao",
  "first_seen_at": 1790800914012,
  "last_seen_at": 1790800914034,
  "last_seen_app_version": null,
  "last_seen_country": null,
  "last_seen_platform": null,
  "last_seen_platform_version": null,
  "active_entitlements": {
    "object": "list",
    "items": [
      {
        "object": "customer.active_entitlement",
        "entitlement_id": "entl1v0bp6r0qs",
        "expires_at": 1793392914000
      }
    ],
    "next_page": null,
    "url": "/v2/projects/proj18pzzkao/customers/user_1/active_entitlements"
  },
  "experiment": null
}

Delete a customer#

DELETE /v2/projects/{project_id}/customers/{customer_id} · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write

Deletes aliases, attributes, subscriptions, purchases, transactions and events. Cannot be undone.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "customer",
  "id": "…",
  "deleted_at": 1790801342625
}

List a customer's app user ids#

GET /v2/projects/{project_id}/customers/{customer_id}/aliases · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/aliases" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of CustomerAlias.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List a customer's attributes#

GET /v2/projects/{project_id}/customers/{customer_id}/attributes · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/attributes" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of CustomerAttribute.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Set a customer's attributes#

POST /v2/projects/{project_id}/customers/{customer_id}/attributes · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write

API writes always win over older SDK writes. A null value deletes the attribute.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Request body (application/json)

Field Type Required Description
attributes array of object yes
attributes[].name string yes
attributes[].value string or null yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/attributes" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"attributes":[{"name":"$displayName","value":"Ana"}]}'

Responses

  • 200: Every attribute of the customer. Returns a list of CustomerAttribute.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List a customer's active entitlements#

GET /v2/projects/{project_id}/customers/{customer_id}/active_entitlements · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/active_entitlements" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of ActiveEntitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List a customer's subscriptions#

GET /v2/projects/{project_id}/customers/{customer_id}/subscriptions · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
environment production, sandbox no Only this environment. Default: both.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/subscriptions" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of subscriptions. Returns a list of Subscription.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "subscription",
      "id": "sub_k1u15wepvw0dfh25",
      "customer_id": "user_1",
      "original_customer_id": "user_1",
      "product_id": "prode0zhpfisko",
      "starts_at": 1790800914000,
      "current_period_starts_at": 1790800914000,
      "current_period_ends_at": 1793392914000,
      "ends_at": 1793392914000,
      "gives_access": true,
      "pending_payment": false,
      "auto_renewal_status": "will_renew",
      "status": "active",
      "total_revenue_in_usd": {
        "currency": "USD",
        "gross": 9.99,
        "commission": 0,
        "tax": 0,
        "proceeds": 9.99
      },
      "presented_offering_id": null,
      "entitlements": {
        "object": "list",
        "items": [
          {
            "object": "entitlement",
            "id": "entl1v0bp6r0qs",
            "project_id": "proj18pzzkao",
            "lookup_key": "pro",
            "display_name": "Pro access",
            "created_at": 1790800901115,
            "state": "active"
          }
        ],
        "next_page": null,
        "url": "/v2/projects/proj18pzzkao/subscriptions/sub_k1u15wepvw0dfh25/entitlements"
      },
      "environment": "sandbox",
      "store": "test_store",
      "store_subscription_identifier": "test_1790800914000_quickstart",
      "ownership": "purchased",
      "management_url": null
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/customers/user_1/subscriptions"
}

List a customer's one-time purchases#

GET /v2/projects/{project_id}/customers/{customer_id}/purchases · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
environment production, sandbox no Only this environment. Default: both.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/purchases" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Purchase.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List a customer's events#

GET /v2/projects/{project_id}/customers/{customer_id}/events · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Newest first. body is the webhook event. Paywall events (PAYWALL_*) only with include_paywall_events=true or when type names them.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
type array of string no Event types (any case); repeat or comma-separate. Naming a paywall type returns it.
include_paywall_events boolean no Also return paywall events (PAYWALL_*). Default false: paywall events are left out unless type names them.
environment production, sandbox no Only this environment. Default: both.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/events" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of CustomerEvent.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Grant an entitlement#

POST /v2/projects/{project_id}/customers/{customer_id}/actions/grant_entitlement · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write

Promotional access until expires_at. A grant ending within 2 hours of an existing grant for the same entitlement changes nothing.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Request body (application/json)

Field Type Required Description
entitlement_id string yes Entitlement id (entl...).
expires_at integer yes Epoch milliseconds, in the future.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/actions/grant_entitlement" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"entitlement_id":"entl1v0bp6r0qs","expires_at":1830000000000}'

Responses

  • 201: The customer. Returns Customer.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Revoke a granted entitlement#

POST /v2/projects/{project_id}/customers/{customer_id}/actions/revoke_granted_entitlement · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Request body (application/json)

Field Type Required Description
entitlement_id string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/actions/revoke_granted_entitlement" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The customer. Returns Customer.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Assign an offering to a customer#

POST /v2/projects/{project_id}/customers/{customer_id}/actions/assign_offering · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read, customer_information:customers:read_write

The customer sees this offering as current. null removes the override.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Request body (application/json)

Field Type Required Description
offering_id string or null yes Offering id (ofrng...) or null.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/actions/assign_offering" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"offering_id":"ofrngjfr71v5awb"}'

Responses

  • 200: Done.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{}

Transfer a customer's purchases to another customer#

POST /v2/projects/{project_id}/customers/{customer_id}/actions/transfer · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write, customer_information:subscriptions:read_write, customer_information:purchases:read_write

Moves subscriptions, one-time purchases and their transactions, optionally only those of the listed apps, and records a TRANSFER event. The target customer is created if it does not exist.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Request body (application/json)

Field Type Required Description
target_customer_id string yes
app_ids array of string no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/actions/transfer" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"target_customer_id":"user_2"}'

Responses

  • 200: Both customers after the transfer.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Get the Customer Center configuration#

GET /v2/projects/{project_id}/customers/{customer_id}/customer_center · Auth: secret key or dashboard session · Permissions: customer_information:customers:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
platform ios, android, macos, web, amazon no
locale string no

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/customer_center" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The configuration.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Restore a purchase by its store order id#

POST /v2/projects/{project_id}/customers/{customer_id}/actions/restore_purchase_by_order_id · Auth: secret key or dashboard session · Permissions: customer_information:customers:read_write

Finds the purchase an order id paid for and gives it to the customer, like a restore from the device: the project's transfer behaviour applies, and a purchase that moves records a TRANSFER event.

  • Google Play order ids (GPA.1234-5678-9012-34567, renewals with ..0, ..1): orders.batchGet on each Play app with a service account gives the purchase token, which is verified and acknowledged like a receipt. The service account needs the "View financial data" permission.
  • App Store order ids (the id on the customer's receipt email, such as MK5TTTVWJH): Apple's Look Up Order ID on each App Store app with an In-App Purchase key, production first, then the sandbox. Only the order's own subscriptions and purchases are restored. RevenueCat's operation takes Google Play order ids only; App Store order ids are a RevenueDot addition.

404 when no store knows the order, 422 unprocessable_entity_error when no app has the credentials the lookup needs, 422 store_error with retryable: true while the store cannot be reached, 409 when the project's transfer behaviour is keep and another customer owns the purchase.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Request body (application/json)

Field Type Required Description
order_id string yes The store order id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/actions/restore_purchase_by_order_id" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"order_id":"GPA.3372-4157-7914-56870"}'

Responses

  • 200: The customer after the restore. Returns Customer.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

List the win-back offers Apple lets a customer redeem#

GET /v2/projects/{project_id}/customers/{customer_id}/win_back_offers · Auth: secret key or dashboard session · RevenueDot extension · Permissions: customer_information:subscriptions:read

One item per App Store subscription of the customer, with the win-back offer ids from Apple's renewal info, best first. RevenueDot reads the renewal info when the app posts a receipt, when Apple sends a notification, and after store actions; it needs the app's In-App Purchase key. See Win-back offers.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/win_back_offers" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The customer's App Store subscriptions.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "win_back_offer_eligibility",
      "subscription_id": "sub_4kq0x2m9a7c1d8e3",
      "product_id": "pro_monthly",
      "store": "app_store",
      "offer_ids": [
        "comeback_50"
      ],
      "updated_at": 1790800914034
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/customers/user_1/win_back_offers"
}

Subscriptions#

Subscriptions across customers, and store actions on them.

Find subscriptions by store id#

GET /v2/projects/{project_id}/subscriptions · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
store_subscription_identifier string yes Store transaction id, original transaction id or purchase token.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Subscription.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get a subscription#

GET /v2/projects/{project_id}/subscriptions/{subscription_id} · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id (sub_...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The subscription. Returns Subscription.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "subscription",
  "id": "sub_k1u15wepvw0dfh25",
  "customer_id": "user_1",
  "original_customer_id": "user_1",
  "product_id": "prode0zhpfisko",
  "starts_at": 1790800914000,
  "current_period_starts_at": 1790800914000,
  "current_period_ends_at": 1793392914000,
  "ends_at": 1793392914000,
  "gives_access": true,
  "pending_payment": false,
  "auto_renewal_status": "will_renew",
  "status": "active",
  "total_revenue_in_usd": {
    "currency": "USD",
    "gross": 9.99,
    "commission": 0,
    "tax": 0,
    "proceeds": 9.99
  },
  "presented_offering_id": null,
  "entitlements": {
    "object": "list",
    "items": [
      {
        "object": "entitlement",
        "id": "entl1v0bp6r0qs",
        "project_id": "proj18pzzkao",
        "lookup_key": "pro",
        "display_name": "Pro access",
        "created_at": 1790800901115,
        "state": "active"
      }
    ],
    "next_page": null,
    "url": "/v2/projects/proj18pzzkao/subscriptions/sub_k1u15wepvw0dfh25/entitlements"
  },
  "environment": "sandbox",
  "store": "test_store",
  "store_subscription_identifier": "test_1790800914000_quickstart",
  "ownership": "purchased",
  "management_url": null
}

List the entitlements a subscription unlocks#

GET /v2/projects/{project_id}/subscriptions/{subscription_id}/entitlements · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/entitlements" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Entitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List a subscription's payments#

GET /v2/projects/{project_id}/subscriptions/{subscription_id}/transactions · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read

One item per paid store transaction of the subscription (purchase, trial start, renewal). A refunded payment's effective_expiration_date is the refund time.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id.

Query parameters

Name Type Required Description
sort id, purchased_at no Default id.
direction asc, desc no Default asc.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/transactions" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of SubscriptionTransaction.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Cancel a subscription (Google Play)#

POST /v2/projects/{project_id}/subscriptions/{subscription_id}/actions/cancel · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read_write

Google Play only: turns auto-renew off. Other stores answer 422.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/actions/cancel" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The subscription. Returns Subscription.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.
  • 503: The store could not be reached, or the feature is not configured on this server. Returns V2Error.

Refund and revoke a subscription (Google Play)#

POST /v2/projects/{project_id}/subscriptions/{subscription_id}/actions/refund · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read_write

Google Play only: refunds the latest payment and ends access now. App Store refunds go through Apple. Other stores answer 422.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/actions/refund" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The subscription. Returns Subscription.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.
  • 503: The store could not be reached, or the feature is not configured on this server. Returns V2Error.

Extend a subscription#

POST /v2/projects/{project_id}/subscriptions/{subscription_id}/actions/extend · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read_write

App Store: Apple extends the renewal date (1 to 90 days, extend_reason_code required, needs the in-app purchase key). Google Play: the renewal is deferred (up to 365 days). Send extend_by_days or extend_until_ms, not both.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id.

Request body (application/json)

Field Type Required Description
extend_by_days integer yes
extend_reason_code undeclared, customer_satisfaction, other, service_issue_or_outage no Apple's reason for the extension. Required for App Store subscriptions.
extend_until_ms integer yes New end, epoch milliseconds.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/actions/extend" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"extend_by_days":7,"extend_reason_code":"customer_satisfaction"}'

Responses

  • 200: The subscription. Returns Subscription.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.
  • 503: The store could not be reached, or the feature is not configured on this server. Returns V2Error.

Refund one payment of a subscription (Google Play)#

POST /v2/projects/{project_id}/subscriptions/{subscription_id}/transactions/{transaction_id}/actions/refund · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes Subscription id.
transaction_id string yes Google order id of the payment.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/transactions/$TRANSACTION_ID/actions/refund" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The refunded payment. Returns SubscriptionTransaction.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.
  • 503: The store could not be reached, or the feature is not configured on this server. Returns V2Error.

Get where the customer manages a subscription#

GET /v2/projects/{project_id}/subscriptions/{subscription_id}/authenticated_management_url · Auth: secret key or dashboard session · Permissions: customer_information:subscriptions:read

The App Store subscriptions page or the Google Play page for the subscription. Null for stores without one.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
subscription_id string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/subscriptions/$SUBSCRIPTION_ID/authenticated_management_url" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The URL.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "authenticated_management_url",
  "management_url": "https://apps.apple.com/account/subscriptions"
}

Purchases#

One-time purchases across customers.

Find one-time purchases by store id#

GET /v2/projects/{project_id}/purchases · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
store_purchase_identifier string yes Store transaction id.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/purchases" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Purchase.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get a one-time purchase#

GET /v2/projects/{project_id}/purchases/{purchase_id} · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
purchase_id string yes Purchase id.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/purchases/$PURCHASE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The purchase. Returns Purchase.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List the entitlements a purchase unlocks#

GET /v2/projects/{project_id}/purchases/{purchase_id}/entitlements · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
purchase_id string yes Purchase id.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/purchases/$PURCHASE_ID/entitlements" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Entitlement.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Refund a one-time purchase (Google Play)#

POST /v2/projects/{project_id}/purchases/{purchase_id}/actions/refund · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read_write

Google Play refunds and revokes the order. Other stores answer 422.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
purchase_id string yes Purchase id.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/purchases/$PURCHASE_ID/actions/refund" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The purchase. Returns Purchase.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.
  • 503: The store could not be reached, or the feature is not configured on this server. Returns V2Error.

Metrics#

The dashboard overview numbers and revenue totals.

Overview metrics#

GET /v2/projects/{project_id}/metrics/overview · Auth: secret key or dashboard session · Permissions: charts_metrics:overview:read

Computed live: active trials, active paid subscriptions, MRR (USD price normalised to a month), revenue in the last 28 days, new and active customers in the last 28 days.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
currency "USD" no Only USD is supported.
environment production, sandbox no RevenueDot extension. Default production.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/metrics/overview" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The metrics. Returns OverviewMetrics.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Revenue over a date range#

GET /v2/projects/{project_id}/metrics/revenue · Auth: secret key or dashboard session · Permissions: charts_metrics:overview:read

Production revenue from the transaction ledger, in USD at the purchase-date rate.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
start_date string yes
end_date string yes Inclusive.
currency string no Only USD for now.
revenue_type revenue, revenue_net_of_taxes, proceeds no Proceeds subtract the estimated store commission. We hold no tax data, so net of taxes equals revenue.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/metrics/revenue" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The total.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "revenue_metric",
  "start_date": "2026-09-01",
  "end_date": "2026-09-30",
  "currency": "USD",
  "value": 12345.67,
  "revenue_type": "revenue"
}

Charts#

Every built-in chart (revenue, MRR, subscriptions, trials, conversion, LTV, churn, refunds, paywalls, ads) with RevenueCat's definitions.

Get chart data#

GET /v2/projects/{project_id}/charts/{chart_name} · Auth: secret key or dashboard session · Permissions: charts_metrics:charts:read

Time series or cohort table for one chart, computed from the project's purchases when asked. Definitions, filters and SQL: https://revenuedot.app/docs/guides/charts.

Sandbox purchases, granted access and Family Sharing are excluded; money is USD at the purchase-date rate (or currency at the same date); periods are UTC.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
chart_name actives, actives_movement, actives_new, arr, churn, cohort_explorer, conversion_to_paying, customers_new, initial_conversion, ltv_per_customer, ltv_per_paying_customer, mrr, mrr_movement, prediction_explorer, refund_rate, refund_request, refunds, revenue, subscription_retention, subscription_status, trials, trials_movement, trials_new, customers_active, trial_conversion, trial_conversion_rate, trial_cancellation, non-subscription_purchases, ad_revenue, ad_impressions, ad_clicks, ad_monetized_customers, ad_arpdau, ad_rpm, ad_fill_rate, ad_ctr, paywall_encounter, paywall_conversion, paywall_ltv, paywall_abandonment, app_store_save_outcomes, play_store_cancel_reasons, customer_center_survey_responses yes The chart. play_store_cancel_reasons and customer_center_survey_responses are RevenueDot names for charts RevenueCat shows only in its dashboard. Definitions: https://revenuedot.app/docs/guides/charts

Query parameters

Name Type Required Description
resolution string no 0–4 or day, week, month, quarter, year. Default day (month for cohort tables). At most 1,000 periods.
start_date string no First day (YYYY-MM-DD). Default: 30 days ago, or 12 months for cohort tables.
end_date string no Last day, inclusive. Default: today.
expand_periods boolean no Count the whole first period of flow charts. Default false.
filters string no JSON array [{"name":"country","values":["US"]}]. Names come from /options.
selectors string no JSON object, e.g. {"revenue_type":"proceeds"}.
segment string no One dimension from /options.
limit_num_segments integer no Top N segments by the first measure; the rest become "Other".
aggregate string no average, total or both, comma separated: values is empty and summary holds only these.
currency USD, EUR, GBP, AUD, CAD, JPY, BRL, KRW, CNY, MXN, SEK, PLN, NZD, CHF no
week_start string no RevenueDot extension: the first day of weekly buckets, 0 (Sunday) to 6 (Saturday) or a day's name. Default 1 (Monday).
include_annotations boolean no
realtime boolean no Accepted for compatibility; every chart uses the real-time (v3) definitions.
environment production, sandbox no RevenueDot extension. sandbox shows only sandbox and Test Store purchases. Default production.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/charts/$CHART_NAME" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The chart.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get available options for a chart#

GET /v2/projects/{project_id}/charts/{chart_name}/options · Auth: secret key or dashboard session · Permissions: charts_metrics:charts:read

Resolutions, segments, filters with the values present in the project's data, and the chart's selectors.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
chart_name actives, actives_movement, actives_new, arr, churn, cohort_explorer, conversion_to_paying, customers_new, initial_conversion, ltv_per_customer, ltv_per_paying_customer, mrr, mrr_movement, prediction_explorer, refund_rate, refund_request, refunds, revenue, subscription_retention, subscription_status, trials, trials_movement, trials_new, customers_active, trial_conversion, trial_conversion_rate, trial_cancellation, non-subscription_purchases, ad_revenue, ad_impressions, ad_clicks, ad_monetized_customers, ad_arpdau, ad_rpm, ad_fill_rate, ad_ctr, paywall_encounter, paywall_conversion, paywall_ltv, paywall_abandonment, app_store_save_outcomes, play_store_cancel_reasons, customer_center_survey_responses yes The chart. play_store_cancel_reasons and customer_center_survey_responses are RevenueDot names for charts RevenueCat shows only in its dashboard. Definitions: https://revenuedot.app/docs/guides/charts

Query parameters

Name Type Required Description
environment production, sandbox no RevenueDot extension. sandbox shows only sandbox and Test Store purchases. Default production.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/charts/$CHART_NAME/options" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The options.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List the customers behind a chart#

GET /v2/projects/{project_id}/charts/{chart_name}/customers · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read, customer_information:customers:read

The customers whose purchases, subscriptions, trials or activity make up the chart for these parameters (the chart's own), most recent contribution first, each with their part of one of the chart's measures. The values plus unattributed_value add up to the chart: over the range (sum: total) or at the last period (sum: last). Which customers each chart lists: https://revenuedot.app/docs/guides/charts#customers-behind-a-chart.

format=csv streams every contributor as CSV (at most 100,000 rows); the response has X-RevenueDot-Total-Count.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
chart_name actives, actives_movement, actives_new, arr, churn, cohort_explorer, conversion_to_paying, customers_new, initial_conversion, ltv_per_customer, ltv_per_paying_customer, mrr, mrr_movement, prediction_explorer, refund_rate, refund_request, refunds, revenue, subscription_retention, subscription_status, trials, trials_movement, trials_new, customers_active, trial_conversion, trial_conversion_rate, trial_cancellation, non-subscription_purchases, ad_revenue, ad_impressions, ad_clicks, ad_monetized_customers, ad_arpdau, ad_rpm, ad_fill_rate, ad_ctr, paywall_encounter, paywall_conversion, paywall_ltv, paywall_abandonment, app_store_save_outcomes, play_store_cancel_reasons, customer_center_survey_responses yes The chart. play_store_cancel_reasons and customer_center_survey_responses are RevenueDot names for charts RevenueCat shows only in its dashboard. Definitions: https://revenuedot.app/docs/guides/charts

Query parameters

Name Type Required Description
resolution string no As for chart data.
start_date string no
end_date string no
expand_periods boolean no
filters string no
selectors string no
segment string no
limit_num_segments integer no
currency USD, EUR, GBP, AUD, CAD, JPY, BRL, KRW, CNY, MXN, SEK, PLN, NZD, CHF no
environment production, sandbox no RevenueDot extension. sandbox shows only sandbox and Test Store purchases. Default production.
limit integer no Customers in items, 1–100. Default 100.
format json, csv no Default json.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/charts/$CHART_NAME/customers" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The customers, or the CSV export.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List chart annotations#

GET /v2/projects/{project_id}/chart_annotations · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read

The project's annotations, oldest first, at most 1,000. With dates, only those that overlap them.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
start_date string no
end_date string no

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_annotations" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The annotations.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a chart annotation#

POST /v2/projects/{project_id}/chart_annotations · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

A note on a UTC day or date range that every chart of the project shows. Viewers cannot create one. Audited as chart_annotation_created.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
title string yes
description string or null no
start_date string yes
end_date string or null no Default start_date; never before it.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_annotations" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"title":"Launched the annual plan","description":"New paywall in 2.4","start_date":"2026-09-14"}'

Responses

  • 201: The annotation.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Get a chart annotation#

GET /v2/projects/{project_id}/chart_annotations/{annotation_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
annotation_id string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_annotations/$ANNOTATION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The annotation.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update a chart annotation#

PATCH /v2/projects/{project_id}/chart_annotations/{annotation_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

Changes any field. A single-day annotation moved with start_date stays a single day; end_date: null makes any annotation a single day. Audited as chart_annotation_updated.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
annotation_id string yes

Request body (application/json)

Field Type Required Description
title string no
description string or null no
start_date string no
end_date string or null no

Example request

Shell
curl -s -X PATCH "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_annotations/$ANNOTATION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The annotation.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete a chart annotation#

DELETE /v2/projects/{project_id}/chart_annotations/{annotation_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
annotation_id string yes

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_annotations/$ANNOTATION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

GET /v2/projects/{project_id}/chart_shares · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read

The project's links that are not revoked, newest first, at most 200.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
chart_name actives, actives_movement, actives_new, arr, churn, cohort_explorer, conversion_to_paying, customers_new, initial_conversion, ltv_per_customer, ltv_per_paying_customer, mrr, mrr_movement, prediction_explorer, refund_rate, refund_request, refunds, revenue, subscription_retention, subscription_status, trials, trials_movement, trials_new, customers_active, trial_conversion, trial_conversion_rate, trial_cancellation, non-subscription_purchases, ad_revenue, ad_impressions, ad_clicks, ad_monetized_customers, ad_arpdau, ad_rpm, ad_fill_rate, ad_ctr, paywall_encounter, paywall_conversion, paywall_ltv, paywall_abandonment, app_store_save_outcomes, play_store_cancel_reasons, customer_center_survey_responses no Only this chart's links.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_shares" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The links.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

POST /v2/projects/{project_id}/chart_shares · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

Computes the chart for the view now and keeps that snapshot (series, labels, summary values; no customer data) behind an unguessable public link with a PNG preview. Owners, admins and developers can create one; at most 200 active per project. Audited as chart_share_created.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
chart_name actives, actives_movement, actives_new, arr, churn, cohort_explorer, conversion_to_paying, customers_new, initial_conversion, ltv_per_customer, ltv_per_paying_customer, mrr, mrr_movement, prediction_explorer, refund_rate, refund_request, refunds, revenue, subscription_retention, subscription_status, trials, trials_movement, trials_new, customers_active, trial_conversion, trial_conversion_rate, trial_cancellation, non-subscription_purchases, ad_revenue, ad_impressions, ad_clicks, ad_monetized_customers, ad_arpdau, ad_rpm, ad_fill_rate, ad_ctr, paywall_encounter, paywall_conversion, paywall_ltv, paywall_abandonment, app_store_save_outcomes, play_store_cancel_reasons, customer_center_survey_responses yes
view object no
view.range string no 7d, 30d, 90d, 12m or custom.
view.start string no Custom range start, YYYY-MM-DD.
view.end string no Custom range end.
view.res string no day, week, month, quarter or year.
view.segment string no
view.filters string no The filters parameter's JSON.
view.sel string no The selectors parameter's JSON.
view.env production, sandbox no
view.compare boolean no Compare to the previous period.
view.type line, stacked_area, column, stacked_column, percent_column no The chart type. Stacked types need two or more series; with one they draw as line or column.
view.m string no The plotted measure group, 0 first.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_shares" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"chart_name":"revenue","view":{"range":"90d","res":"week","segment":"product","type":"stacked_column"}}'

Responses

  • 201: The link.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

DELETE /v2/projects/{project_id}/chart_shares/{share_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

The public page and images answer 410 from now on. Audited as chart_share_deleted.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
share_id string yes The link's id (chartshare…), not its token.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/chart_shares/$SHARE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Revoked.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

List saved charts#

GET /v2/projects/{project_id}/saved_charts · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/saved_charts" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of saved charts.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Save a chart view#

POST /v2/projects/{project_id}/saved_charts · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

A named chart with the dashboard view that produced it (range, dates, resolution, segment, filters, selectors, environment, compare, chart type, measure group). Up to 200 per project.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
name string yes
chart_name actives, actives_movement, actives_new, arr, churn, cohort_explorer, conversion_to_paying, customers_new, initial_conversion, ltv_per_customer, ltv_per_paying_customer, mrr, mrr_movement, prediction_explorer, refund_rate, refund_request, refunds, revenue, subscription_retention, subscription_status, trials, trials_movement, trials_new, customers_active, trial_conversion, trial_conversion_rate, trial_cancellation, non-subscription_purchases, ad_revenue, ad_impressions, ad_clicks, ad_monetized_customers, ad_arpdau, ad_rpm, ad_fill_rate, ad_ctr, paywall_encounter, paywall_conversion, paywall_ltv, paywall_abandonment, app_store_save_outcomes, play_store_cancel_reasons, customer_center_survey_responses yes
view object no
view.range string no 7d, 30d, 90d, 12m or custom.
view.start string no Custom range start, YYYY-MM-DD.
view.end string no Custom range end.
view.res string no day, week, month, quarter or year.
view.segment string no
view.filters string no The filters parameter's JSON.
view.sel string no The selectors parameter's JSON.
view.env production, sandbox no
view.compare boolean no Compare to the previous period.
view.type line, stacked_area, column, stacked_column, percent_column no The chart type. Stacked types need two or more series; with one they draw as line or column.
view.m string no The plotted measure group, 0 first.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/saved_charts" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"MRR by country","chart_name":"mrr","view":{"range":"90d","res":"week","segment":"country","compare":true}}'

Responses

  • 201: The saved chart.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Get a saved chart#

GET /v2/projects/{project_id}/saved_charts/{saved_chart_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
saved_chart_id string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/saved_charts/$SAVED_CHART_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The saved chart.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Rename or update a saved chart#

PATCH /v2/projects/{project_id}/saved_charts/{saved_chart_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
saved_chart_id string yes

Request body (application/json)

Field Type Required Description
name string no
view object no
view.range string no 7d, 30d, 90d, 12m or custom.
view.start string no Custom range start, YYYY-MM-DD.
view.end string no Custom range end.
view.res string no day, week, month, quarter or year.
view.segment string no
view.filters string no The filters parameter's JSON.
view.sel string no The selectors parameter's JSON.
view.env production, sandbox no
view.compare boolean no Compare to the previous period.
view.type line, stacked_area, column, stacked_column, percent_column no The chart type. Stacked types need two or more series; with one they draw as line or column.
view.m string no The plotted measure group, 0 first.

Example request

Shell
curl -s -X PATCH "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/saved_charts/$SAVED_CHART_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The saved chart.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete a saved chart#

DELETE /v2/projects/{project_id}/saved_charts/{saved_chart_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: charts_metrics:charts:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
saved_chart_id string yes

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/saved_charts/$SAVED_CHART_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

In-app currencies#

Currencies your app sells or rewards, their product grants and each customer's balance.

List in-app currencies#

GET /v2/projects/{project_id}/virtual_currencies · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of currencies.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "virtual_currency",
      "project_id": "proj18pzzkao",
      "code": "GLD",
      "name": "Gold",
      "description": null,
      "state": "active",
      "created_at": 1790800901115,
      "product_grants": [
        {
          "object": "virtual_currency.product_grant",
          "product_ids": [
            "prod6n3k1a8w2z"
          ],
          "amount": 100,
          "trial_amount": 0,
          "expire_at_cycle_end": false
        }
      ]
    }
  ],
  "next_page": null,
  "url": "/v2/projects/{project_id}/virtual_currencies"
}

Create an in-app currency#

POST /v2/projects/{project_id}/virtual_currencies · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read_write

A product grant credits the balance each time a purchase, renewal or trial start of one of its products is recorded, once per store transaction.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
code string yes Letters, digits and underscores, up to 10.
name string yes
description string or null no
product_grants array of object no
product_grants[].product_ids array of string yes
product_grants[].amount integer yes Credited per purchase or renewal.
product_grants[].trial_amount integer or null no Credited when a free trial starts. Default 0.
product_grants[].expire_at_cycle_end boolean or null no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"code":"GLD","name":"Gold","product_grants":[{"product_ids":["prod6n3k1a8w2z"],"amount":100}]}'

Responses

  • 201: The currency.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 201 response:

JSON
{
  "object": "virtual_currency",
  "project_id": "proj18pzzkao",
  "code": "GLD",
  "name": "Gold",
  "description": null,
  "state": "active",
  "created_at": 1790800901115,
  "product_grants": [
    {
      "object": "virtual_currency.product_grant",
      "product_ids": [
        "prod6n3k1a8w2z"
      ],
      "amount": 100,
      "trial_amount": 0,
      "expire_at_cycle_end": false
    }
  ]
}

Get an in-app currency#

GET /v2/projects/{project_id}/virtual_currencies/{virtual_currency_code} · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
virtual_currency_code string yes The currency code, such as GLD.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies/$VIRTUAL_CURRENCY_CODE" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The currency.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "virtual_currency",
  "project_id": "proj18pzzkao",
  "code": "GLD",
  "name": "Gold",
  "description": null,
  "state": "active",
  "created_at": 1790800901115,
  "product_grants": [
    {
      "object": "virtual_currency.product_grant",
      "product_ids": [
        "prod6n3k1a8w2z"
      ],
      "amount": 100,
      "trial_amount": 0,
      "expire_at_cycle_end": false
    }
  ]
}

Update an in-app currency#

POST /v2/projects/{project_id}/virtual_currencies/{virtual_currency_code} · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
virtual_currency_code string yes The currency code, such as GLD.

Request body (application/json)

Field Type Required Description
name string no
description string or null no
product_grants array of object no
product_grants[].product_ids array of string yes
product_grants[].amount integer yes Credited per purchase or renewal.
product_grants[].trial_amount integer or null no Credited when a free trial starts. Default 0.
product_grants[].expire_at_cycle_end boolean or null no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies/$VIRTUAL_CURRENCY_CODE" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Gold coins"}'

Responses

  • 200: The currency.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "virtual_currency",
  "project_id": "proj18pzzkao",
  "code": "GLD",
  "name": "Gold",
  "description": null,
  "state": "active",
  "created_at": 1790800901115,
  "product_grants": [
    {
      "object": "virtual_currency.product_grant",
      "product_ids": [
        "prod6n3k1a8w2z"
      ],
      "amount": 100,
      "trial_amount": 0,
      "expire_at_cycle_end": false
    }
  ]
}

Delete an in-app currency#

DELETE /v2/projects/{project_id}/virtual_currencies/{virtual_currency_code} · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read_write

Also deletes every customer's balance of it and its ledger.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
virtual_currency_code string yes The currency code, such as GLD.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies/$VIRTUAL_CURRENCY_CODE" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "virtual_currency",
  "id": "GLD",
  "deleted_at": 1790801342625
}

Archive an in-app currency#

POST /v2/projects/{project_id}/virtual_currencies/{virtual_currency_code}/actions/archive · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read_write

An archived currency stops granting; customers keep a non-zero balance.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
virtual_currency_code string yes The currency code, such as GLD.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies/$VIRTUAL_CURRENCY_CODE/actions/archive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The currency.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "virtual_currency",
  "project_id": "proj18pzzkao",
  "code": "GLD",
  "name": "Gold",
  "description": null,
  "state": "active",
  "created_at": 1790800901115,
  "product_grants": [
    {
      "object": "virtual_currency.product_grant",
      "product_ids": [
        "prod6n3k1a8w2z"
      ],
      "amount": 100,
      "trial_amount": 0,
      "expire_at_cycle_end": false
    }
  ]
}

Unarchive an in-app currency#

POST /v2/projects/{project_id}/virtual_currencies/{virtual_currency_code}/actions/unarchive · Auth: secret key or dashboard session · Permissions: project_configuration:virtual_currencies:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
virtual_currency_code string yes The currency code, such as GLD.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/virtual_currencies/$VIRTUAL_CURRENCY_CODE/actions/unarchive" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The currency.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "virtual_currency",
  "project_id": "proj18pzzkao",
  "code": "GLD",
  "name": "Gold",
  "description": null,
  "state": "active",
  "created_at": 1790800901115,
  "product_grants": [
    {
      "object": "virtual_currency.product_grant",
      "product_ids": [
        "prod6n3k1a8w2z"
      ],
      "amount": 100,
      "trial_amount": 0,
      "expire_at_cycle_end": false
    }
  ]
}

List a customer's balances#

GET /v2/projects/{project_id}/customers/{customer_id}/virtual_currencies · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
include_empty_balances boolean no Also list currencies with a zero balance.
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/virtual_currencies" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Balances.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "virtual_currency_balance",
      "currency_code": "GLD",
      "balance": 100,
      "name": "Gold"
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/customers/user_1/virtual_currencies"
}

Credit or spend in-app currency#

POST /v2/projects/{project_id}/customers/{customer_id}/virtual_currencies/transactions · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read_write

Adds a ledger entry per currency. Send an Idempotency-Key so a retry does not apply twice. Nothing is applied if any balance would go below zero.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
include_empty_balances boolean no Also list currencies with a zero balance.

Headers

Name Type Required Description
Idempotency-Key string no Repeating a request with the same key changes nothing the second time.

Request body (application/json)

Field Type Required Description
adjustments object yes Signed change per currency code. A balance cannot go below zero.
reference string or null no Your own note, kept in the ledger.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/virtual_currencies/transactions" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"adjustments":{"GLD":-20},"reference":"level 3 unlock"}'

Responses

  • 200: The balances after the change.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "virtual_currency_balance",
      "currency_code": "GLD",
      "balance": 100,
      "name": "Gold"
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/customers/user_1/virtual_currencies"
}

Change a balance without a ledger entry#

POST /v2/projects/{project_id}/customers/{customer_id}/virtual_currencies/update_balance · Auth: secret key or dashboard session · Permissions: customer_information:purchases:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
include_empty_balances boolean no Also list currencies with a zero balance.

Headers

Name Type Required Description
Idempotency-Key string no Repeating a request with the same key changes nothing the second time.

Request body (application/json)

Field Type Required Description
adjustments object yes Signed change per currency code. A balance cannot go below zero.
reference string or null no Your own note, kept in the ledger.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/virtual_currencies/update_balance" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"adjustments":{"GLD":-20},"reference":"level 3 unlock"}'

Responses

  • 200: The balances after the change.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "virtual_currency_balance",
      "currency_code": "GLD",
      "balance": 100,
      "name": "Gold"
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/customers/user_1/virtual_currencies"
}

Audit log#

Who changed what in a project.

List audit log entries#

GET /v2/projects/{project_id}/audit_logs · Auth: secret key or dashboard session · Permissions: project_configuration:audit_logs:read

Who changed what, newest first. Every successful write through API v2 is recorded with the actor (a user, a secret key, or an OAuth client). Reads and request bodies are never recorded.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.
start_date string no
end_date string no Inclusive.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audit_logs" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of entries.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "audit_log",
      "id": "log1ab2c3d4e5",
      "project_id": "proj18pzzkao",
      "action_type": "entitlement_created",
      "target_type": "entitlement",
      "target_identifier": "entl1v0bp6r0qs",
      "actor_type": "api_key",
      "actor_identifier": "key_08ec817fce",
      "occurred_at": 1790801342634,
      "additional_data": {
        "method": "POST",
        "status": 201
      }
    }
  ],
  "next_page": null,
  "url": "/v2/projects/{project_id}/audit_logs"
}

Targeting#

Audiences, and rules that pick the offering and placement offerings for each customer.

List audiences#

GET /v2/projects/{project_id}/audiences · Auth: secret key or dashboard session · Permissions: audiences:audiences:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: All audiences.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create an audience#

POST /v2/projects/{project_id}/audiences · Auth: secret key or dashboard session · Permissions: audiences:audiences:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
name string yes
rules object yes
rules.groups array of object yes Groups are OR-ed; conditions in a group are AND-ed.
rules.groups[].conditions array of object yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Gold plan","rules":{"groups":[{"conditions":[{"field":"customAttribute:plan","operator":"is","value":"gold"}]}]}}'

Responses

  • 201: The audience.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Preview who matches#

POST /v2/projects/{project_id}/audiences/actions/preview · Auth: secret key or dashboard session · Permissions: audiences:audiences:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences/actions/preview" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"rules":{"groups":[{"conditions":[{"field":"country","operator":"isAnyOf","value":"US,CA"}]}]}}'

Responses

  • 200: Stats and a sample.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Known values for attribution and custom-attribute fields#

GET /v2/projects/{project_id}/audiences/filter_options · Auth: secret key or dashboard session · Permissions: audiences:audiences:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
fields string no Comma-separated: mediaSource, campaign, adGroup, ad, keyword, creative, latestProduct, customAttribute:.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences/filter_options" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Options per field.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get an audience#

GET /v2/projects/{project_id}/audiences/{audience_id} · Auth: secret key or dashboard session · Permissions: audiences:audiences:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
audience_id string yes

Query parameters

Name Type Required Description
expand array of stats, customer_sample, used_by no

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences/$AUDIENCE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The audience.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update an audience#

POST /v2/projects/{project_id}/audiences/{audience_id} · Auth: secret key or dashboard session · Permissions: audiences:audiences:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
audience_id string yes

Request body (application/json)

Field Type Required Description
name string no
rules object no
rules.groups array of object yes Groups are OR-ed; conditions in a group are AND-ed.
rules.groups[].conditions array of object yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences/$AUDIENCE_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Gold"}'

Responses

  • 200: The audience.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete an unused audience#

DELETE /v2/projects/{project_id}/audiences/{audience_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: audiences:audiences:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
audience_id string yes

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/audiences/$AUDIENCE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

List targeting rules in order#

GET /v2/projects/{project_id}/targeting_rules · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/targeting_rules" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: All rules.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a targeting rule#

POST /v2/projects/{project_id}/targeting_rules · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Added at the end of the order, inactive unless state is active. When the SDK fetches offerings, the first live rule whose audience matches decides the current offering and the offering per placement.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
name string yes
audience_id string or null no
offering_id string yes
placements object no
state active, inactive no
starts_at integer or null no
ends_at integer or null no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/targeting_rules" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Gold gets promo","audience_id":"aud1a2b3c4d5e6f","offering_id":"ofrngm2u3h89blc","placements":{"onboarding_end":"ofrng9x8y7z6w5"},"state":"active"}'

Responses

  • 201: The rule.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Set the evaluation order#

POST /v2/projects/{project_id}/targeting_rules/actions/reorder · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
rule_ids array of string yes Every rule of the project, once, first evaluated first.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/targeting_rules/actions/reorder" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: All rules in the new order.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get a targeting rule#

GET /v2/projects/{project_id}/targeting_rules/{rule_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
rule_id string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/targeting_rules/$RULE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The rule.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update a targeting rule#

POST /v2/projects/{project_id}/targeting_rules/{rule_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
rule_id string yes

Request body (application/json)

Field Type Required Description
name string no
audience_id string or null no
offering_id string no
placements object no
state active, inactive no
starts_at integer or null no
ends_at integer or null no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/targeting_rules/$RULE_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"state":"inactive"}'

Responses

  • 200: The rule; revision goes up by one.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete a targeting rule#

DELETE /v2/projects/{project_id}/targeting_rules/{rule_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
rule_id string yes

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/targeting_rules/$RULE_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Experiments#

Offering experiments: a control and up to three treatments, each with an offering and placement offerings; enrollment of new or new and existing customers, a saved or custom audience, a share, and a priority order between experiments; results with 95% intervals, lift and the chance to beat the control for 18 metrics, a daily series, CSV export and a 7-day audience estimate. See Experiments.

List experiments#

GET /v2/projects/{project_id}/experiments · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Oldest first. priority gives the enrollment order.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of experiments. Returns a list of Experiment.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create an offering experiment#

POST /v2/projects/{project_id}/experiments · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Creates a draft at the bottom of the enrollment order (the highest priority). Send variants (a control and 1 to 3 treatments), or the older offering_a and offering_b for two variants. Defaults: type other, the type's metrics, enrollment new, everyone, 100%.

Once started, a customer who asks for offerings and is admitted (enrollment mode, then audience, then the share) joins one variant for good and gets its offering as current_offering_id and its placements. Enrolling records one EXPERIMENT_ENROLLMENT event, and the customer's lifecycle events carry experiments.

Answers 400 when: both variants and offering_a/offering_b are sent, or neither; audience_id and audience_rules are both sent; the audience, an offering or a placement offering is not in the project, or the offering is archived; a condition's field or operator is unknown; a placement id has other characters; a variant's id does not match its position; two variants serve the same offering and the same placement offerings; or enrollment is new_and_existing with track_paywall_views: false.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
name string yes 1 to 256 characters.
type introductory_offer, free_trial_offer, paywall_design, price_point, subscription_duration, subscription_ordering, other no What is tested. It sets the default metrics: see Experiments.
primary_metric initial_conversion_rate, trial_conversion_rate, conversion_to_paying, refund_rate, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr_per_customer, mrr_per_paying_customer no The metric that decides the winner: a rate or a per-customer mean, because those have an interval.
secondary_metrics array of initial_conversion_rate, initial_conversions, trials_started, trials_completed, trials_converted, trial_conversion_rate, paid_customers, conversion_to_paying, active_subscribers, churned_subscribers, refunded_customers, refund_rate, realized_ltv, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr, mrr_per_customer, mrr_per_paying_customer no Up to 12 more metrics shown first in the results.
notes string no The hypothesis, in Markdown.
enrollment new, new_and_existing no new: only customers first seen at or after the experiment's first start. new_and_existing: anyone who asks for offerings while it runs.
track_paywall_views boolean no Default false. Set to true with new_and_existing; false there answers 400.
audience_id string or null no A saved audience. Send it or audience_rules, not both; setting one clears the other.
audience_rules object or null no Conditions written for this experiment only, in the audience condition format. Null when it uses a saved audience or everyone.
audience_rules.groups array of object yes Groups are OR-ed; conditions in a group are AND-ed.
audience_rules.groups[].conditions array of object yes
enrollment_percent integer no Share of matching customers to enroll. Default 100.
variants array of object no The control first, then 1 to 3 treatments.
variants[].id a, b, c, d no Optional; must match the position (a, b, c, d).
variants[].name string no Default: Control, Treatment B ...
variants[].offering_id string yes Offering id in this project.
variants[].placements object no Placement id (letters, digits, _, ., -, up to 100) → offering id, or null for no paywall.
offering_a string no Older form: the control offering. Send it with offering_b instead of variants.
offering_b string no Older form: the treatment offering.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Price point test","type":"price_point","notes":"## Hypothesis\n$14.99 a month earns more per customer than $9.99.","variants":[{"offering_id":"ofrngm2u3h89blc"},{"name":"Higher price","offering_id":"ofrng9x8y7z6w5a"}],"audience_rules":{"groups":[{"conditions":[{"field":"country","operator":"isAnyOf","value":"US"}]}]},"enrollment_percent":50}'

Responses

  • 201: The draft. Returns Experiment.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 201 response:

JSON
{
  "object": "experiment",
  "id": "prexp4k2m9q8z1x",
  "project_id": "proj18pzzkao",
  "name": "Price point test",
  "type": "price_point",
  "status": "draft",
  "primary_metric": "realized_ltv_per_customer",
  "secondary_metrics": [
    "conversion_to_paying",
    "initial_conversion_rate",
    "refund_rate"
  ],
  "notes": "## Hypothesis\n$14.99 a month earns more per customer than $9.99.",
  "enrollment": "new",
  "track_paywall_views": false,
  "audience_id": null,
  "audience_rules": {
    "groups": [
      {
        "conditions": [
          {
            "field": "country",
            "operator": "isAnyOf",
            "value": "US"
          }
        ]
      }
    ]
  },
  "enrollment_percent": 50,
  "priority": 3,
  "variants": [
    {
      "id": "a",
      "name": "Control",
      "offering_id": "ofrngm2u3h89blc",
      "placements": {}
    },
    {
      "id": "b",
      "name": "Higher price",
      "offering_id": "ofrng9x8y7z6w5a",
      "placements": {}
    }
  ],
  "started_at": null,
  "paused_at": null,
  "stopped_at": null,
  "created_at": 1790800914012,
  "updated_at": null,
  "enrolled_customers": 0
}

Set the enrollment order#

POST /v2/projects/{project_id}/experiments/actions/reorder · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

When several running experiments could take the same customer, the one with the lowest priority enrolls them. Stopped experiments keep their relative order after these.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
experiment_ids array of string yes Every draft, running and paused experiment of the project, once, first enrolling first.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/actions/reorder" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"experiment_ids":["prexp7h3k1m0p2q","prexp4k2m9q8z1x"]}'

Responses

  • 200: Every experiment of the project in priority order, stopped ones last. Returns a list of Experiment.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Estimate how many customers would join#

POST /v2/projects/{project_id}/experiments/actions/estimate · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read, audiences:audiences:read

What the dashboard's create form shows: customers of the last 7 days who match the audience, times the percentage, split between the variants. Changes nothing.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
audience_id string or null no A saved audience. Send it or audience_rules, not both.
audience_rules object or null no Conditions written for this experiment only, in the audience condition format. Null when it uses a saved audience or everyone.
audience_rules.groups array of object yes Groups are OR-ed; conditions in a group are AND-ed.
audience_rules.groups[].conditions array of object yes
enrollment new, new_and_existing no new (default) counts customers first seen in the last 7 days; new_and_existing counts customers seen in them.
enrollment_percent integer no Default 100.
variant_count integer no Default 2.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/actions/estimate" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"enrollment":"new","audience_rules":{"groups":[{"conditions":[{"field":"country","operator":"isAnyOf","value":"US"}]}]},"enrollment_percent":50,"variant_count":2}'

Responses

  • 200: The estimate. Returns ExperimentEstimate.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "experiment_estimate",
  "period_days": 7,
  "matching_customers": 1840,
  "enrolled_customers": 920,
  "customers_per_variant": 460,
  "is_approximate": false
}

Get an experiment#

GET /v2/projects/{project_id}/experiments/{experiment_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The experiment. Returns Experiment.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update an experiment#

POST /v2/projects/{project_id}/experiments/{experiment_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

A draft takes every field, with the same checks as create. offering_a and offering_b replace the first two variants' offerings and keep their names and placements. Once an experiment has started (running, paused or stopped), only name, type, primary_metric, secondary_metrics, notes and enrollment_percent can change; any other field answers 422 and names it.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Request body (application/json)

Field Type Required Description
name string no 1 to 256 characters.
type introductory_offer, free_trial_offer, paywall_design, price_point, subscription_duration, subscription_ordering, other no What is tested. It sets the default metrics: see Experiments.
primary_metric initial_conversion_rate, trial_conversion_rate, conversion_to_paying, refund_rate, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr_per_customer, mrr_per_paying_customer no The metric that decides the winner: a rate or a per-customer mean, because those have an interval.
secondary_metrics array of initial_conversion_rate, initial_conversions, trials_started, trials_completed, trials_converted, trial_conversion_rate, paid_customers, conversion_to_paying, active_subscribers, churned_subscribers, refunded_customers, refund_rate, realized_ltv, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr, mrr_per_customer, mrr_per_paying_customer no Up to 12 more metrics shown first in the results.
notes string no The hypothesis, in Markdown.
enrollment new, new_and_existing no new: only customers first seen at or after the experiment's first start. new_and_existing: anyone who asks for offerings while it runs.
track_paywall_views boolean no Default false. Set to true with new_and_existing; false there answers 400.
audience_id string or null no A saved audience. Send it or audience_rules, not both; setting one clears the other.
audience_rules object or null no Conditions written for this experiment only, in the audience condition format. Null when it uses a saved audience or everyone.
audience_rules.groups array of object yes Groups are OR-ed; conditions in a group are AND-ed.
audience_rules.groups[].conditions array of object yes
enrollment_percent integer no Share of matching customers to enroll. Default 100.
variants array of object no The control first, then 1 to 3 treatments.
variants[].id a, b, c, d no Optional; must match the position (a, b, c, d).
variants[].name string no Default: Control, Treatment B ...
variants[].offering_id string yes Offering id in this project.
variants[].placements object no Placement id (letters, digits, _, ., -, up to 100) → offering id, or null for no paywall.
offering_a string no Older form: the control offering. Send it with offering_b instead of variants.
offering_b string no Older form: the treatment offering.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"enrollment_percent":100,"notes":"Raised to 100% after a week."}'

Responses

  • 200: The experiment. Returns Experiment.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Delete an experiment#

DELETE /v2/projects/{project_id}/experiments/{experiment_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Deletes its enrollments and results. On their next request its customers get what targeting gives them, or join another running experiment that admits them. A running experiment answers 422: stop or pause it first.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Start or resume#

POST /v2/projects/{project_id}/experiments/{experiment_id}/actions/start · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

A draft or paused experiment runs. The first start sets started_at; a resume clears paused_at and keeps started_at. Answers 422 for a running or stopped experiment, when one of its offerings was deleted or archived, or when it has fewer than two variants; 409 (resource_locked_error) when another request changed its status at the same time.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID/actions/start" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The experiment. Returns Experiment.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Pause: enrolled customers keep their variant, nobody new joins#

POST /v2/projects/{project_id}/experiments/{experiment_id}/actions/pause · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Only a running experiment can pause (422 otherwise; 409 when another request changed its status at the same time). Results keep counting what enrolled customers do.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID/actions/pause" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The experiment. Returns Experiment.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Stop for good#

POST /v2/projects/{project_id}/experiments/{experiment_id}/actions/stop · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

A running or paused experiment stops (422 otherwise; 409 when another request changed its status at the same time). On their next request its customers get what targeting gives them, or join another running experiment that admits them. Results stay and keep updating as renewals and refunds arrive. A stopped experiment never enrolls anyone again; duplicate it instead.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID/actions/stop" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The experiment. Returns Experiment.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Results per variant#

GET /v2/projects/{project_id}/experiments/{experiment_id}/results · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Every metric per variant, computed now from the enrolled customers' purchases made after they joined (and the renewals, refunds and trial conversions that follow), in USD. Production results leave out customers who joined from a test device (a Test Store app or an iOS sandbox build); environment=sandbox counts every enrolled customer with their test purchases. Above 25,000 enrolled customers the numbers come from a fixed random sample of 25,000, and sample says so. Rates have a Wilson interval; per-customer means a normal interval; treatments also have the lift over the control with its interval and the chance to beat the control. guidance says whether there is enough data and how many customers a 20% lift needs. series holds every metric by day.

The first release's fields stay: conversions, conversion_rate, trials, paying_customers, revenue and revenue_per_customer on each variant, and chance_b_beats_a and enough_data at the top. See Experiments for every definition and the statistics.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Query parameters

Name Type Required Description
environment production, sandbox no Default production. sandbox counts test purchases instead.
platform string no Only customers whose last request came from this platform (any case), such as ios or android.
country string no Only customers whose last request came from this country (ISO 3166-1 alpha-2, any case).
paywall all, viewed, not_viewed no Customers with or without a paywall view after joining. Default viewed when the experiment tracks paywall views, else all.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID/results" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Results. Returns ExperimentResults.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Export results as CSV#

GET /v2/projects/{project_id}/experiments/{experiment_id}/results/export · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

The same numbers as the results, as an RFC 4180 CSV with CRLF line ends, named experiment-<id>-<kind>-<environment>-<YYYY-MM-DD>.csv. Summary columns: variant_id, variant_name, offering_id, customers, metric, metric_name, value, numerator, denominator, lower_95, upper_95, lift, lift_lower_95, lift_upper_95, chance_to_beat_control. Daily columns: date (UTC), variant_id, variant_name, then each metric id. Empty cells are values that do not apply; text that a spreadsheet would run as a formula starts with an apostrophe.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
experiment_id string yes Experiment id (prexp...).

Query parameters

Name Type Required Description
kind summary, daily no summary (default): one row per variant and metric. daily: one row per day and variant, one column per metric id.
environment production, sandbox no Default production. sandbox counts test purchases instead.
platform string no Only customers whose last request came from this platform (any case), such as ios or android.
country string no Only customers whose last request came from this country (ISO 3166-1 alpha-2, any case).
paywall all, viewed, not_viewed no Customers with or without a paywall view after joining. Default viewed when the experiment tracks paywall views, else all.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/experiments/$EXPERIMENT_ID/results/export" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The CSV file, as an attachment.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Paywalls#

Paywall components the SDK renders, their publishing and versions, and the images and fonts they use.

List paywalls#

GET /v2/projects/{project_id}/paywalls · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.
expand array of items.offering no

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of paywalls.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a paywall#

POST /v2/projects/{project_id}/paywalls · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Either { offering_id } for an empty paywall on that offering, a full draft with components_config and components_localizations, or (RevenueDot extension) { template_id } for a gallery template built with the offering's packages (see GET /paywall_templates). An offering has at most one paywall. Nothing reaches the SDK until it is published.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"offering_id":"ofrngm2u3h89blc","template_id":"trial_timeline","template_options":{"app_name":"Scanner","accent_color":"#2563eb","terms_url":"https://example.com/terms","privacy_url":"https://example.com/privacy"}}'

Responses

  • 201: The paywall.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 201 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Get a paywall#

GET /v2/projects/{project_id}/paywalls/{paywall_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Query parameters

Name Type Required Description
expand array of offering, components no

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The paywall.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Update a paywall's draft#

PATCH /v2/projects/{project_id}/paywalls/{paywall_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Send the revision you read. A different revision answers 409 so two editors never overwrite each other. The draft starts from the published version when there are no unpublished changes.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Request body (application/json)

Field Type Required Description
revision integer yes
components_config object no
components_localizations object no
default_locale string no
offering_id string or null no
name string or null no
automatically_scale_font_size boolean no
exit_offers object or null no
state_declarations object or null no
play_store_product_change_mode object or null no

Example request

Shell
curl -s -X PATCH "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"revision":3,"components_localizations":{"en_US":{"headline":"Go Pro"}}}'

Responses

  • 200: The paywall.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Delete a paywall#

DELETE /v2/projects/{project_id}/paywalls/{paywall_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "deleted_at": 1790801342625
}

Publish a paywall#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/actions/publish · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

The draft becomes what the SDK receives in paywall_components for the paywall's offering (and as a workflow in remote config). Needs an offering and unpublished changes, and the components must decode in the SDKs: otherwise 422 names the first problem (POST /paywalls/validate lists all). Locales missing a string are served the default locale's.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/actions/publish" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The paywall.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Unpublish a paywall#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/actions/unpublish · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

The SDK stops receiving it. The content is kept as the draft.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/actions/unpublish" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The paywall.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Attach an offering to a paywall#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/actions/attach_offering · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Request body (application/json)

Field Type Required Description
offering_id string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/actions/attach_offering" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"offering_id":"ofrngm2u3h89blc"}'

Responses

  • 200: The paywall.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Detach the offering from a paywall#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/actions/detach_offering · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/actions/detach_offering" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The paywall.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "paywall",
  "id": "pw1a2b3c4d5e6f7g8",
  "name": "Go Pro",
  "offering_id": "ofrngm2u3h89blc",
  "created_at": 1790800901115,
  "published_at": 1790801342625,
  "automatically_scale_font_size": true,
  "revision": 3
}

Duplicate a paywall#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/actions/duplicate · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Copies the draft (default) or the published version into a new unpublished paywall, optionally on a new offering.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Request body (application/json)

Field Type Required Description
name string no
source_version draft, published no
offering object no
offering.lookup_key string yes
offering.display_name string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/actions/duplicate" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"source_version":"published","offering":{"lookup_key":"summer","display_name":"Summer sale"}}'

Responses

  • 201: The new paywall.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.

List saved snapshots#

GET /v2/projects/{project_id}/paywalls/{paywall_id}/versions · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/versions" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of snapshots (without their content).
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Save a named snapshot#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/versions · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Request body (application/json)

Field Type Required Description
name string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/versions" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Before the summer test"}'

Responses

  • 201: The snapshot.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Restore a snapshot into the draft#

POST /v2/projects/{project_id}/paywalls/{paywall_id}/versions/{version_id}/actions/restore · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

The snapshot becomes the draft (the revision bumps). Publish to send it to apps.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).
version_id string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/versions/$VERSION_ID/actions/restore" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The paywall with components.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get a snapshot#

GET /v2/projects/{project_id}/paywalls/{paywall_id}/versions/{version_id} · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).
version_id string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/versions/$VERSION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The snapshot.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Get the template form of a paywall#

GET /v2/projects/{project_id}/paywalls/{paywall_id}/template · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

The dashboard's template form (headline, features, colours, package labels) that produced the draft, so the editor can reopen it. Null for paywalls made another way.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/template" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The form.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Store the template form of a paywall#

PUT /v2/projects/{project_id}/paywalls/{paywall_id}/template · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
paywall_id string yes Paywall id (pw...).

Request body (application/json)

Field Type Required Description
template object or null yes

Example request

Shell
curl -s -X PUT "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/$PAYWALL_ID/template" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"template":{"template":"classic","headline":"Unlock everything"}}'

Responses

  • 200: The form.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

GET /v2/projects/{project_id}/paywall_templates · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

The ten gallery layouts with the fields the dashboard filters on. Create a paywall from one with POST /paywalls and template_id. icon_base_url is where the built-in icons are served.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywall_templates" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The templates.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Validate paywall components#

POST /v2/projects/{project_id}/paywalls/validate · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

Checks components JSON the way the SDKs decode it, without saving: errors stop publishing (the SDK would fail or render it wrong), warnings do not. With repair: true it first fills missing required fields and inline texts (the same repair as the AI generator) and returns the repaired JSON and what it fixed. With offering_id, packages are checked against the offering.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
components_config object yes
components_localizations object yes
default_locale string no
offering_id string or null no
repair boolean no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/validate" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"components_config":{"base":{"stack":{"type":"stack","components":[{"type":"text","text":"Go Pro"}]}}},"components_localizations":{},"repair":true}'

Responses

  • 200: The result.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Whether the AI generator is available#

GET /v2/projects/{project_id}/paywalls/ai · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read

RevenueDot Cloud uses GPT-6 Luna through the Vercel AI Gateway. A self-hosted server needs AI_GATEWAY_API_KEY, OPENAI_API_KEY or ANTHROPIC_API_KEY; without one, available is false.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/ai" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The generator.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Generate a paywall with AI#

POST /v2/projects/{project_id}/paywalls/generate · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Designs a paywall with the language model and returns it without saving. The model first reads the prompt into a brief (plans, trial, benefits, look), then designs the paywall; a checker holds the design to the brief and sends problems back for up to two fixes. The result always passes validation. Save it with POST /paywalls. One generation every 5 seconds and 60 a day per project.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
prompt string yes
app_name string no
brand_colors array of string no
offering_id string or null no
locale string no

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/paywalls/generate" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"prompt":"A calm sleep app, explain the 7-day trial, yearly first","app_name":"Calm","brand_colors":["#0f766e"],"offering_id":"ofrngm2u3h89blc"}'

Responses

  • 200: A paywall draft.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 429: Too many requests. Retry later. Returns V2Error.
  • 502: An upstream service (the store or the language model) gave no usable answer. Retry later. Returns V2Error.
  • 503: The store could not be reached, or the feature is not configured on this server. Returns V2Error.

List images#

GET /v2/projects/{project_id}/media_assets · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/media_assets" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of images.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Upload an image#

POST /v2/projects/{project_id}/media_assets · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

Up to about 2 MB. Width and height are read from PNG, JPEG and WebP files. A project holds up to 200 assets.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
filename string yes
content_type image/jpeg, image/png, image/avif, image/heic, image/heif, image/webp yes
file_data_base64 string yes Base64 file bytes.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/media_assets" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 201: The image.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

List fonts#

GET /v2/projects/{project_id}/fonts · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/fonts" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of fonts.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Upload a font#

POST /v2/projects/{project_id}/fonts · Auth: secret key or dashboard session · Permissions: project_configuration:offerings:read_write

A .ttf or .otf file. Its PostScript name, family, style and weight are read from the file.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
filename string yes
content_type font/ttf, font/otf yes
file_data_base64 string yes Base64 file bytes.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/fonts" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 201: The font.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Download a paywall image or font#

GET /assets/{project_id}/{object_name} · Auth: none

Public and cached for a year (Cache-Control: immutable, a strong ETag, 304 on If-None-Match): object names are random and never change content. The SDK reads asset_base_url + object name. On Cloud repeat downloads come from Cloudflare's edge cache.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
object_name string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/assets/$PROJECT_ID/$OBJECT_NAME"

Responses

  • 200: The file bytes with their content type.
  • 404: No such asset.

Download a built-in paywall icon#

GET /assets/icons/{file} · Auth: none · RevenueDot extension

The icons that icon and timeline components use (base_url + formats.heic). Cached for a year.

Path parameters

Name Type Required Description
file string yes {name}.png (96 × 96, white on transparent; the SDKs tint it), .heic and .webp names serve the same PNG, or {name}.svg.

Example request

Shell
curl -s "$REVENUEDOT_URL/assets/icons/$FILE"

Responses

  • 200: The image.
  • 404: No such icon.

Delete an uploaded font#

DELETE /v2/projects/{project_id}/fonts/{font_id} · Auth: secret key or dashboard session · RevenueDot extension · Permissions: project_configuration:offerings:read_write

Paywalls that still name the font show the system font in the SDKs.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
font_id string yes Starts with fnt.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/fonts/$FONT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Webhook integrations#

Where events are sent.

List webhooks#

GET /v2/projects/{project_id}/integrations/webhooks · Auth: secret key or dashboard session · Permissions: project_configuration:integrations:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/integrations/webhooks" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of WebhookIntegration.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Create a webhook#

POST /v2/projects/{project_id}/integrations/webhooks · Auth: secret key or dashboard session · Permissions: project_configuration:integrations:read_write

The answer includes signing_secret (whsec_...) once. Store it: it verifies the X-RevenueCat-Webhook-Signature header. See Webhooks.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
name string yes
url string yes http(s) URL.
authorization_header string or null no Sent as the Authorization header.
environment production, sandbox, null no Null or absent: both.
event_types array of initial_purchase, renewal, product_change, cancellation, billing_issue, non_renewing_purchase, uncancellation, transfer, subscription_paused, expiration, subscription_extended, invoice_issuance, temporary_entitlement_grant, refund_reversed, virtual_currency_transaction, test, experiment_enrollment, purchase_redeemed, subscriber_alias, price_increase_consent_required, price_increase_consent_approved, funnel_viewed, funnel_step_completed, funnel_purchase, paywall_impression, paywall_close, paywall_cancel, paywall_exit_offer, paywall_component_interacted, paywall_purchase_initiated, paywall_purchase_error no Empty or absent: every type except the opt-in ones (subscriber_alias, the three RevenueDot funnel types and the seven paywall types), which are sent only when named here.
app_id string or null no Only this app's events.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/integrations/webhooks" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Backend","url":"https://api.example.com/webhooks/revenuedot","authorization_header":"Bearer my-shared-token","environment":"production","event_types":["initial_purchase","renewal"]}'

Responses

  • 201: The webhook with its signing secret. Returns WebhookIntegration.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 201 response:

JSON
{
  "object": "webhook_integration",
  "id": "wh_ceps8nr7mczvhaqw",
  "project_id": "proj18pzzkao",
  "name": "Backend",
  "url": "https://api.example.com/webhooks/revenuedot",
  "environment": "production",
  "event_types": [
    "initial_purchase",
    "renewal"
  ],
  "app_id": null,
  "created_at": 1790801342625,
  "signing_secret": "whsec_3f5b7fb5a591c17aaa9108376df0bddbe1555f0a908bfdc0"
}

Get a webhook#

GET /v2/projects/{project_id}/integrations/webhooks/{webhook_integration_id} · Auth: secret key or dashboard session · Permissions: project_configuration:integrations:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
webhook_integration_id string yes Webhook id (wh_...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/integrations/webhooks/$WEBHOOK_INTEGRATION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The webhook. Returns WebhookIntegration.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Update a webhook#

POST /v2/projects/{project_id}/integrations/webhooks/{webhook_integration_id} · Auth: secret key or dashboard session · Permissions: project_configuration:integrations:read_write

enabled is a RevenueDot extension: false pauses deliveries without deleting the webhook. Events recorded while it is off are not sent; queued retries resume when it is turned on. Read it with GET /v2/projects/{project_id}/webhooks.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
webhook_integration_id string yes Webhook id.

Request body (application/json)

Field Type Required Description
name string no
url string no
authorization_header string or null no
environment string or null no
event_types array of string no
app_id string or null no
enabled boolean no RevenueDot extension. False pauses deliveries.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/integrations/webhooks/$WEBHOOK_INTEGRATION_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"enabled":false}'

Responses

  • 200: The webhook. Returns WebhookIntegration.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Delete a webhook#

DELETE /v2/projects/{project_id}/integrations/webhooks/{webhook_integration_id} · Auth: secret key or dashboard session · Permissions: project_configuration:integrations:read_write

Pending deliveries are deleted with it.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
webhook_integration_id string yes Webhook id.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/integrations/webhooks/$WEBHOOK_INTEGRATION_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "webhook_integration",
  "id": "…",
  "deleted_at": 1790801342625
}

Discounts#

Web discounts for RevenueDot's web checkout, with RevenueCat's v2 discount operations and shapes. Each discount is a Stripe coupon and each code a Stripe promotion code in your own Stripe account. See Web discounts.

List discounts#

GET /v2/projects/{project_id}/discounts · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read

The project's web discounts in RevenueCat's Discount shape. RevenueDot's extra settings (max_redemptions, expires_at), the codes and the Stripe ids are on GET /web_discounts.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of discounts. Returns a list of Discount.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "discount",
      "id": "disc5k2m9q4x7a1b3c",
      "identifier": "spring20",
      "customer_facing_name": "Spring sale",
      "duration_mode": "time_window",
      "eligibility": "everyone",
      "time_window": "P3M",
      "disabled_at": null,
      "type": "percentage",
      "percentage": 20,
      "created_at": 1790800901115,
      "updated_at": 1790801342625
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/discounts"
}

Create a discount#

POST /v2/projects/{project_id}/discounts · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Creates the discount and a Stripe coupon for it in every Stripe app of the project that has a key: percent_off, or amount_off and currency with currency_options for the other currencies; duration once, repeating with duration_in_months, or forever; applies_to.products from product_identifiers; max_redemptions; redeem_by from expires_at. Add codes with POST /discounts/{discount_id}/discount_codes, or set it as a purchase link's or paywall step's automatic discount.

max_redemptions and expires_at are RevenueDot additions to RevenueCat's request. 409 when the identifier exists. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved. See Web discounts.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Request body (application/json)

Field Type Required Description
identifier string yes Letters, digits, _ . -.
customer_facing_name string yes
type percentage, fixed_amount yes
percentage integer no For percentage: 1 to 100.
fixed_amounts object no For fixed_amount: amount off by currency, keyed by the currency code.
duration_mode one_time, time_window, forever yes
eligibility everyone, never_purchased, never_subscribed, never_subscribed_to_the_same_product yes
time_window string no For time_window: whole months or years, 1 to 36 months (P3M, P1Y). Stripe repeats a coupon only by months.
product_identifiers array of string no Store identifiers (the Stripe price id of a web product) or product ids. Empty or absent: every product.
max_redemptions integer or null no RevenueDot addition: paid checkouts it may be used in. Sent to Stripe as the coupon's max_redemptions.
expires_at integer or null no RevenueDot addition: when it stops working, epoch milliseconds. Sent to Stripe as redeem_by.

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"identifier":"spring20","customer_facing_name":"Spring sale","type":"percentage","percentage":20,"duration_mode":"time_window","time_window":"P3M","eligibility":"everyone","max_redemptions":100}'

Responses

  • 201: The discount. Returns Discount.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 201 response:

JSON
{
  "object": "discount",
  "id": "disc5k2m9q4x7a1b3c",
  "identifier": "spring20",
  "customer_facing_name": "Spring sale",
  "duration_mode": "time_window",
  "eligibility": "everyone",
  "time_window": "P3M",
  "disabled_at": null,
  "type": "percentage",
  "percentage": 20,
  "created_at": 1790800901115,
  "updated_at": 1790801342625
}

Get a discount#

GET /v2/projects/{project_id}/discounts/{discount_id} · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The discount. Returns Discount.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "discount",
  "id": "disc8h3n1v6w0z2y4d",
  "identifier": "five_off",
  "customer_facing_name": "$5 off",
  "duration_mode": "one_time",
  "eligibility": "never_purchased",
  "time_window": null,
  "disabled_at": null,
  "type": "fixed_amount",
  "fixed_amount": {
    "USD": 5,
    "EUR": 4.5
  },
  "created_at": 1790800901115,
  "updated_at": 1790801342625
}

Update a discount#

PATCH /v2/projects/{project_id}/discounts/{discount_id} · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Send only what changes. A Stripe coupon cannot change its amount or duration, so a change to type, percentage, fixed_amounts, duration_mode, time_window, product_identifiers, max_redemptions or expires_at creates a new coupon and new promotion codes, and turns the old promotion codes off. Subscriptions that already use the old coupon keep it. A new name or eligibility changes nothing in Stripe. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Request body (application/json)

Field Type Required Description
customer_facing_name string no
type percentage, fixed_amount no
percentage integer no For percentage: 1 to 100.
fixed_amounts object no For fixed_amount: amount off by currency, keyed by the currency code.
duration_mode one_time, time_window, forever no
eligibility everyone, never_purchased, never_subscribed, never_subscribed_to_the_same_product no
time_window string no For time_window: whole months or years, 1 to 36 months (P3M, P1Y). Stripe repeats a coupon only by months.
product_identifiers array of string no Store identifiers (the Stripe price id of a web product) or product ids. Empty or absent: every product.
max_redemptions integer or null no RevenueDot addition: paid checkouts it may be used in. Sent to Stripe as the coupon's max_redemptions.
expires_at integer or null no RevenueDot addition: when it stops working, epoch milliseconds. Sent to Stripe as redeem_by.

Example request

Shell
curl -s -X PATCH "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"percentage":30,"customer_facing_name":"Spring sale 30"}'

Responses

  • 200: The discount. Returns Discount.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "discount",
  "id": "disc5k2m9q4x7a1b3c",
  "identifier": "spring20",
  "customer_facing_name": "Spring sale 30",
  "duration_mode": "time_window",
  "eligibility": "everyone",
  "time_window": "P3M",
  "disabled_at": null,
  "type": "percentage",
  "percentage": 30,
  "created_at": 1790800901115,
  "updated_at": 1790801342625
}

Delete a discount#

DELETE /v2/projects/{project_id}/discounts/{discount_id} · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Turns its promotion codes off and deletes its Stripe coupons. Subscriptions that already use the coupon keep the discount, as in Stripe. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "discount",
  "id": "disc5k2m9q4x7a1b3c",
  "deleted_at": 1790801342625
}

Enable a discount#

POST /v2/projects/{project_id}/discounts/{discount_id}/actions/enable · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Checkout accepts it again and its Stripe promotion codes are turned back on. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID/actions/enable" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The discount. Returns Discount.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "discount",
  "id": "disc5k2m9q4x7a1b3c",
  "identifier": "spring20",
  "customer_facing_name": "Spring sale",
  "duration_mode": "time_window",
  "eligibility": "everyone",
  "time_window": "P3M",
  "disabled_at": null,
  "type": "percentage",
  "percentage": 20,
  "created_at": 1790800901115,
  "updated_at": 1790801342625
}

Disable a discount#

POST /v2/projects/{project_id}/discounts/{discount_id}/actions/disable · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Checkout refuses it ("This code is no longer active.") and its Stripe promotion codes are turned off. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID/actions/disable" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: The discount. Returns Discount.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "discount",
  "id": "disc5k2m9q4x7a1b3c",
  "identifier": "spring20",
  "customer_facing_name": "Spring sale",
  "duration_mode": "time_window",
  "eligibility": "everyone",
  "time_window": "P3M",
  "disabled_at": 1790801342625,
  "type": "percentage",
  "percentage": 20,
  "created_at": 1790800901115,
  "updated_at": 1790801342625
}

List a discount's codes#

GET /v2/projects/{project_id}/discounts/{discount_id}/discount_codes · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID/discount_codes" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of codes. Returns a list of DiscountCode.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [
    {
      "object": "discount_code",
      "code": "SPRING20",
      "created_at": 1790800901115
    }
  ],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/discounts/disc5k2m9q4x7a1b3c/discount_codes"
}

Create discount codes#

POST /v2/projects/{project_id}/discounts/{discount_id}/discount_codes · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Each code becomes a Stripe promotion code on the discount's coupon, active unless the discount is disabled. Codes are unique in the project whatever their case (409 when one is taken). Letters, digits, _ and -. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).

Request body (application/json)

Field Type Required Description
codes array of string yes

Example request

Shell
curl -s -X POST "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID/discount_codes" -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"codes":["SPRING20","friends"]}'

Responses

  • 201: The new codes.
  • 400: The request is invalid. Returns V2Error.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 409: It already exists, or it conflicts with another object. Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 201 response:

JSON
[
  {
    "object": "discount_code",
    "code": "SPRING20",
    "created_at": 1790800901115
  },
  {
    "object": "discount_code",
    "code": "friends",
    "created_at": 1790800901115
  }
]

Delete a discount code#

DELETE /v2/projects/{project_id}/discounts/{discount_id}/discount_codes/{discount_code} · Auth: secret key or dashboard session · Permissions: project_configuration:discounts:read_write

Its Stripe promotion code is turned off. Stripe errors answer 422 store_error (retryable: true while Stripe is unavailable) and nothing is saved.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
discount_id string yes Discount id (disc...).
discount_code string yes The code, URL-encoded. Any case.

Example request

Shell
curl -s -X DELETE "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/discounts/$DISCOUNT_ID/discount_codes/$DISCOUNT_CODE" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Deleted. Returns Deleted.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.
  • 422: The request is valid but cannot be done in this state or for this store. Returns V2Error.

Example 200 response:

JSON
{
  "object": "discount_code",
  "id": "friends",
  "deleted_at": 1790801342625
}

Invoices#

RevenueCat Billing invoices. Stripe issues the invoices for RevenueDot's web checkout, so these answer on purpose: the list is empty and a file is 404.

List a customer's invoices#

GET /v2/projects/{project_id}/customers/{customer_id}/invoices · Auth: secret key or dashboard session · Permissions: customer_information:invoices:read

Always an empty list for a known customer; 404 for an unknown one. Invoices belong to RevenueCat Billing, which issues its own. For web purchases through RevenueDot's checkout, Stripe issues the invoices in your Stripe account.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.

Query parameters

Name Type Required Description
limit integer no Page size. Values outside 1-100 are clamped, not rejected.
starting_after string no Id of the last item of the previous page. Use next_page instead of building it.

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/invoices" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: Always an empty list.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Example 200 response:

JSON
{
  "object": "list",
  "items": [],
  "next_page": null,
  "url": "/v2/projects/proj18pzzkao/customers/user_1/invoices"
}

Download an invoice#

GET /v2/projects/{project_id}/customers/{customer_id}/invoices/{invoice_id}/file · Auth: secret key or dashboard session · Permissions: customer_information:invoices:read

Answers 404 resource_missing: there is no invoice. Invoices belong to RevenueCat Billing, which issues its own. For web purchases through RevenueDot's checkout, Stripe issues the invoices in your Stripe account.

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).
customer_id string yes Any app user id of the customer.
invoice_id string yes

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/customers/user_1/invoices/$INVOICE_ID/file" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 401: No API key, or an unknown one. Returns V2Error.
  • 402: Live data is paused: the project's owner went live more than 14 days ago without starting Pro (RevenueDot Cloud only). Sandbox reads (environment=sandbox) and secret-key reads of one customer, subscription or purchase are never paused. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Collaborators#

Dashboard users of the project.

List collaborators#

GET /v2/projects/{project_id}/collaborators · Auth: secret key or dashboard session · Permissions: project_configuration:collaborators:read

Path parameters

Name Type Required Description
project_id string yes Project id (proj...).

Example request

Shell
curl -s "$REVENUEDOT_URL/v2/projects/$PROJECT_ID/collaborators" -H "Authorization: Bearer $SECRET_KEY"

Responses

  • 200: A page of results. Returns a list of Collaborator.
  • 401: No API key, or an unknown one. Returns V2Error.
  • 403: The key lacks a permission, or a public key was used. Returns V2Error.
  • 404: Not found in this project (another project's ids also answer 404). Returns V2Error.

Objects#

The shapes the operations above send and return.

ActiveEntitlement#

Field Type Required Description
object "customer.active_entitlement" yes
entitlement_id string yes Entitlement id (entl...), not the lookup key.
expires_at integer or null yes When access ends. Epoch milliseconds, or null.

App#

Only the object for the app's own type is present. Store secrets are never returned.

Field Type Required Description
object "app" yes
id string yes App id (app...).
name string yes
created_at integer yes Creation time. Epoch milliseconds.
type amazon, app_store, mac_app_store, play_store, stripe, rc_billing, roku, paddle, test_store, galaxy yes
project_id string yes
custom_url_scheme string no Derived from the public key.
app_store object no
app_store.bundle_id string no
app_store.app_store_connect_api_key_configured boolean no
app_store.subscription_key_configured boolean no True when the in-app purchase key (.p8, key id, issuer id) is set.
app_store.app_store_connect_vendor_number string or null no
mac_app_store object no
mac_app_store.bundle_id string no
play_store object no
play_store.package_name string no
play_store.play_service_account_credentials_configured boolean no
amazon object no
amazon.package_name string no
stripe object no
stripe.stripe_account_id string or null no
rc_billing object no
rc_billing.stripe_account_id string or null no
rc_billing.seller_company_name string no
rc_billing.app_name string no
rc_billing.support_email string or null no
rc_billing.default_currency string no
roku object no
roku.roku_channel_id string or null no
roku.roku_channel_name string or null no
paddle object no
paddle.paddle_is_sandbox boolean no True for a sandbox key (pdl_sdbx_apikey_…), or for an older key marked sandbox.
paddle.paddle_api_key null no Always null: the key is never returned (RevenueCat's field).
galaxy object no RevenueDot extension.
galaxy.package_name string no

Collaborator#

Field Type Required Description
object "collaborator" yes
id string yes
name string or null no
email string yes
role admin, developer, read_only yes RevenueCat's role names. read_only is the dashboard's Viewer role.
accepted_at integer no When the user joined. Epoch milliseconds.
has_mfa boolean no Always false.

Customer#

active_entitlements and experiment are present on single-customer answers; attributes only with expand=attributes.

Field Type Required Description
object "customer" yes
id string yes The customer's original app user id.
project_id string yes
first_seen_at integer yes First seen. Epoch milliseconds.
last_seen_at integer or null yes Last seen. Epoch milliseconds, or null.
last_seen_app_version string or null no
last_seen_country string or null no
last_seen_platform string or null no
last_seen_platform_version null no
active_entitlements object no
active_entitlements.object "list" yes
active_entitlements.items array of ActiveEntitlement yes
active_entitlements.next_page string or null yes Path of the next page, or null on the last page.
active_entitlements.url string yes Path of this list.
experiment ExperimentEnrollment or null no The experiment the customer is in (running or paused), else the last one they joined, or null.
attributes object no
attributes.object "list" yes
attributes.items array of CustomerAttribute yes
attributes.next_page string or null yes Path of the next page, or null on the last page.
attributes.url string yes Path of this list.

CustomerAlias#

Field Type Required Description
object "customer.alias" yes
id string yes An app user id of the customer.
created_at integer yes When it was linked. Epoch milliseconds.

CustomerAttribute#

Field Type Required Description
object "customer.attribute" yes
name string yes
value string yes
updated_at integer yes Last update. Epoch milliseconds.

CustomerEvent#

Field Type Required Description
object "customer.event" yes
id string yes
app_id string or null no
type string yes Webhook event type, for example INITIAL_PURCHASE.
body object yes The webhook event object.
created_at integer yes Recorded. Epoch milliseconds.
occurred_at integer yes When it happened. Epoch milliseconds.

Deleted#

Field Type Required Description
object string yes The deleted object's type.
id string yes
deleted_at integer yes When it was deleted. Epoch milliseconds.

Discount#

A web discount, in RevenueCat's Discount shape. Each one is a Stripe coupon in every Stripe app of the project.

Field Type Required Description
object discount yes
id string yes Discount id (disc...).
identifier string yes Your identifier for the discount, unique in the project.
customer_facing_name string yes The name buyers see at checkout and Stripe puts on the coupon (first 40 characters).
duration_mode one_time, time_window, forever yes one_time: the first payment. time_window: every payment for time_window. forever: every payment.
eligibility everyone, never_purchased, never_subscribed, never_subscribed_to_the_same_product yes Who may use it, checked against the buyer's purchase history when the checkout has an app user id.
time_window string or null no ISO 8601 months or years (P3M, P1Y), 1 to 36 months, for time_window. Otherwise null.
disabled_at integer or null no When it was disabled. Epoch milliseconds, or null.
type percentage yes
percentage integer yes Percent off, 1 to 100.
created_at integer yes When it was created. Epoch milliseconds.
updated_at integer yes When it last changed. Epoch milliseconds.
fixed_amount object yes Amount off by currency code, in major units: { "USD": 5, "EUR": 4.5 }.

DiscountCode#

Field Type Required Description
object discount_code yes
code string yes The code buyers type. Matched without regard to case.
created_at integer yes When it was created. Epoch milliseconds.

DiscountFixedAmountVariant#

A fixed amount discount (RevenueCat's shape).

Field Type Required Description
object discount yes
id string yes Discount id (disc...).
identifier string yes Your identifier for the discount, unique in the project.
customer_facing_name string yes The name buyers see at checkout and Stripe puts on the coupon (first 40 characters).
duration_mode one_time, time_window, forever yes one_time: the first payment. time_window: every payment for time_window. forever: every payment.
eligibility everyone, never_purchased, never_subscribed, never_subscribed_to_the_same_product yes Who may use it, checked against the buyer's purchase history when the checkout has an app user id.
time_window string or null no ISO 8601 months or years (P3M, P1Y), 1 to 36 months, for time_window. Otherwise null.
disabled_at integer or null no When it was disabled. Epoch milliseconds, or null.
type fixed_amount yes
fixed_amount object yes Amount off by currency code, in major units: { "USD": 5, "EUR": 4.5 }.
created_at integer yes When it was created. Epoch milliseconds.
updated_at integer yes When it last changed. Epoch milliseconds.

DiscountPercentageVariant#

A percentage discount (RevenueCat's shape).

Field Type Required Description
object discount yes
id string yes Discount id (disc...).
identifier string yes Your identifier for the discount, unique in the project.
customer_facing_name string yes The name buyers see at checkout and Stripe puts on the coupon (first 40 characters).
duration_mode one_time, time_window, forever yes one_time: the first payment. time_window: every payment for time_window. forever: every payment.
eligibility everyone, never_purchased, never_subscribed, never_subscribed_to_the_same_product yes Who may use it, checked against the buyer's purchase history when the checkout has an app user id.
time_window string or null no ISO 8601 months or years (P3M, P1Y), 1 to 36 months, for time_window. Otherwise null.
disabled_at integer or null no When it was disabled. Epoch milliseconds, or null.
type percentage yes
percentage integer yes Percent off, 1 to 100.
created_at integer yes When it was created. Epoch milliseconds.
updated_at integer yes When it last changed. Epoch milliseconds.

Entitlement#

Field Type Required Description
object "entitlement" yes
id string yes Entitlement id (entl...).
project_id string yes
lookup_key string yes What apps check, for example pro.
display_name string yes
created_at integer yes Creation time. Epoch milliseconds.
state active, inactive yes
products object no
products.object "list" yes
products.items array of Product yes
products.next_page string or null yes Path of the next page, or null on the last page.
products.url string yes Path of this list.

Experiment#

Field Type Required Description
object "experiment" yes
id string yes Experiment id (prexp...).
project_id string yes
name string yes
type introductory_offer, free_trial_offer, paywall_design, price_point, subscription_duration, subscription_ordering, other yes What is tested. It sets the default metrics: see Experiments.
status draft, running, paused, stopped yes draft → running ⇄ paused → stopped. A stopped experiment cannot run again.
primary_metric initial_conversion_rate, trial_conversion_rate, conversion_to_paying, refund_rate, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr_per_customer, mrr_per_paying_customer yes The metric that decides the winner: a rate or a per-customer mean, because those have an interval.
secondary_metrics array of initial_conversion_rate, initial_conversions, trials_started, trials_completed, trials_converted, trial_conversion_rate, paid_customers, conversion_to_paying, active_subscribers, churned_subscribers, refunded_customers, refund_rate, realized_ltv, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr, mrr_per_customer, mrr_per_paying_customer yes Up to 12 more metrics shown first in the results.
notes string yes The hypothesis, in Markdown (up to 20,000 characters).
enrollment new, new_and_existing yes new: only customers first seen at or after the experiment's first start. new_and_existing: anyone who asks for offerings while it runs.
track_paywall_views boolean yes Results count paywall views (SDK paywall_impression and custom_paywall_impression events) and default to customers who saw a paywall. Turned on for every experiment made or changed to new_and_existing; A/B experiments converted from the first release keep false.
audience_id string or null yes A saved audience (aud...). Null with audience_rules or for everyone.
audience_rules object or null yes Conditions written for this experiment only, in the audience condition format. Null when it uses a saved audience or everyone.
audience_rules.groups array of object yes Groups are OR-ed; conditions in a group are AND-ed.
audience_rules.groups[].conditions array of object yes
enrollment_percent integer yes Share of matching customers enrolled, 1 to 100.
priority integer yes Enrollment order among the project's experiments, 1 first. New experiments go last; change it with the reorder action.
variants array of ExperimentVariant yes The control first, then 1 to 3 treatments. Customers are split evenly.
started_at integer or null yes First start. A resume keeps it, so new keeps counting from the first start. Epoch milliseconds, or null.
paused_at integer or null yes Last pause; cleared on resume. Epoch milliseconds, or null.
stopped_at integer or null yes Stopped. Epoch milliseconds, or null.
created_at integer yes Created. Epoch milliseconds.
updated_at integer or null yes Last change. Epoch milliseconds, or null.
enrolled_customers integer yes Customers enrolled so far, sandbox included.

ExperimentEnrollment#

Field Type Required Description
object "experiment_enrollment" yes
id string yes Experiment id (prexp...).
name string yes The experiment's name.
variant a, b, c, d yes The customer's variant: a is the control.

ExperimentEstimate#

Field Type Required Description
object "experiment_estimate" yes
period_days integer yes Always 7.
matching_customers integer yes Customers first seen (new) or seen (new_and_existing) in the last 7 days who match the audience.
enrolled_customers integer yes matching_customers × enrollment_percent, rounded.
customers_per_variant integer yes enrolled_customers ÷ variant_count, rounded down.
is_approximate boolean yes True when more than 5,000 customers were seen: the audience share of the 5,000 most recent is scaled to all of them.

ExperimentMetric#

Field Type Required Description
id initial_conversion_rate, initial_conversions, trials_started, trials_completed, trials_converted, trial_conversion_rate, paid_customers, conversion_to_paying, active_subscribers, churned_subscribers, refunded_customers, refund_rate, realized_ltv, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr, mrr_per_customer, mrr_per_paying_customer yes
display_name string yes
kind rate, mean, count, total yes rate: numerator ÷ denominator with a Wilson interval. mean: per-customer average with a normal interval. count and total: no interval.
unit %, $, # yes Rates are fractions (0.12 is 12%); money is USD.
better higher, lower yes Which direction wins. Churned subscribers, refunded customers and refund rate are better when lower.
description string yes

ExperimentMetricValue#

Counts and totals carry only value. The control has no lift or chance_to_beat_control fields.

Field Type Required Description
value number or null yes The metric now. Null for a rate or mean with no customers in its denominator.
numerator integer no Rates: the customers or trials counted.
denominator integer no Rates: the customers, trials or paid customers it divides by. Means: the customers averaged.
lower number or null no Rates and means: the 95% interval's lower bound.
upper number or null no Rates and means: the 95% interval's upper bound.
lift number or null no Treatments, rates and means: value ÷ control value − 1 (0.12 is 12% above the control). Null when the control's value is 0.
lift_lower number or null no The lift's 95% interval, by the delta method on the log of the ratio (Katz's interval for rates, with half counts added when a rate is 0% or 100%). Null for a mean with fewer than two customers on a side, or a mean of 0.
lift_upper number or null no Upper bound of the lift's 95% interval.
chance_to_beat_control number or null no Treatments, rates and means: the probability this variant beats the control in the metric's better direction. Null for a mean with fewer than two customers on a side.

ExperimentResults#

Field Type Required Description
object "experiment_results" yes
experiment_id string yes
environment production, sandbox yes
currency "USD" yes
computed_at integer yes Computed. Epoch milliseconds.
primary_metric initial_conversion_rate, trial_conversion_rate, conversion_to_paying, refund_rate, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr_per_customer, mrr_per_paying_customer yes
secondary_metrics array of initial_conversion_rate, initial_conversions, trials_started, trials_completed, trials_converted, trial_conversion_rate, paid_customers, conversion_to_paying, active_subscribers, churned_subscribers, refunded_customers, refund_rate, realized_ltv, realized_ltv_per_customer, realized_ltv_per_paying_customer, mrr, mrr_per_customer, mrr_per_paying_customer yes
control_variant_id string yes Always a.
filters object yes
filters.platform string or null yes The platform filter, or null.
filters.country string or null yes The country filter, or null.
filters.paywall all, viewed, not_viewed yes The paywall filter in effect, after the default.
filter_options object yes
filter_options.platforms array of string yes Platforms of the enrolled customers' last requests.
filter_options.countries array of string yes Countries of the enrolled customers' last requests.
sample object or null no Null when every enrolled customer is counted. Above 25,000 enrolled customers the results come from a fixed random sample of 25,000 (the same customers on every request): rates, means, intervals and chances are estimates from it, and counts and totals are the sample's.
sample.customers integer yes Customers in the sample: 25,000.
sample.enrolled_customers integer yes Every enrolled customer in this environment.
sample.enrolled_by_variant object yes Variant id → its enrolled customers.
metrics array of ExperimentMetric yes Every metric's definition, in the order the dashboard lists them.
variants object yes One entry per variant, the control first.
variants.object "list" yes
variants.items array of ExperimentVariantResult yes
variants.next_page string or null yes Path of the next page, or null on the last page.
variants.url string yes Path of this list.
guidance object yes
guidance.enough_data boolean yes Every variant has at least min_customers customers and min_events events of the primary metric.
guidance.min_customers integer yes 100.
guidance.min_events integer yes 10 events per variant: conversions for initial conversion rate, paid customers for conversion to paying, completed trials for trial conversion rate, and paid customers for refund rate and the per-customer means.
guidance.customers_needed_per_variant integer or null yes Customers per variant to detect a 20% relative lift on the primary metric at 95% confidence and 80% power, from the control's current value. Null until the control has data.
guidance.leader object or null yes The treatment most likely to beat the control on the primary metric.
guidance.leader.variant_id string yes
guidance.leader.chance_to_beat_control number yes
guidance.message string yes One sentence for people, such as "Too early to call ...".
series object yes
series.days array of integer yes Start of each UTC day from the first start to now (at most the last 400 days). Epoch milliseconds.
series.values object yes values[metric_id][variant_id][i]: the metric as of the end of days[i], cumulative.
chance_b_beats_a number yes Kept from the first release: variant b's chance to beat the control on initial_conversion_rate (0.5 when unknown).
enough_data boolean yes Kept: guidance.enough_data.

ExperimentVariant#

Field Type Required Description
id a, b, c, d yes Set by position: a is the control, then b, c, d.
name string yes Defaults to Control, Treatment B, Treatment C, Treatment D.
offering_id string yes The offering Offerings.current returns to customers in this variant (ofrng...). A deleted offering keeps its id here.
placements object yes Placement id → offering id for customers in this variant; null shows no paywall there. It overlays the placements of the targeting rule that matches the customer.

ExperimentVariantResult#

Field Type Required Description
id a, b, c, d yes
name string yes
offering_id string or null yes The variant's offering id.
customers integer yes Enrolled customers who pass the filters (in the sample, when sample is set). Production results leave out customers who joined from a test device.
paywall_viewers integer yes Of those, customers with a paywall view after joining.
metrics object yes Every metric id → its value, interval, lift and chance to beat the control.
conversions integer yes Kept from the first results release: initial_conversions.
conversion_rate number yes Kept: initial_conversion_rate, 4 decimals (0 when there are no customers).
trials integer yes Kept: trials_started.
paying_customers integer yes Kept: paid_customers.
revenue number yes Kept: realized_ltv, USD.
revenue_per_customer number yes Kept: realized_ltv_per_customer, USD (0 when there are no customers).

IndicativePrice#

Field Type Required Description
object "indicative_price" yes
currency string yes ISO 4217 code.
country string or null yes US for a United States store price, the region code for another Google Play region, else null (Test Store and Stripe prices, other App Store territories).
amount_micros integer yes Price in micros: 9.99 is 9990000.

MonetaryAmount#

Field Type Required Description
currency string yes ISO 4217 currency code.
gross number yes Gross amount.
commission number yes Estimated store commission.
tax number yes Tax. Always 0 today.
proceeds number yes Gross minus commission.

Offering#

Field Type Required Description
object "offering" yes
id string yes Offering id (ofrng...).
lookup_key string yes
display_name string yes
is_current boolean yes Exactly one offering per project is current.
created_at integer yes Creation time. Epoch milliseconds.
project_id string yes
state active, inactive yes
paywall_id string or null no The paywall attached to this offering, or null.
metadata object or null yes
packages object no
packages.object "list" yes
packages.items array of Package yes
packages.next_page string or null yes Path of the next page, or null on the last page.
packages.url string yes Path of this list.

OverviewMetrics#

Field Type Required Description
object "overview_metrics" yes
currency "USD" yes
metrics array of object yes
metrics[].object "overview_metric" no
metrics[].id active_trials, active_subscriptions, mrr, revenue, new_customers, active_users no
metrics[].name string no
metrics[].description string no
metrics[].unit #, $ no
metrics[].period P0D, P28D no
metrics[].value number no
metrics[].last_updated_at integer no Computed at. Epoch milliseconds.
metrics[].last_updated_at_iso8601 string no

Package#

Field Type Required Description
object "package" yes
id string yes Package id (pkge...).
lookup_key string yes For example $rc_monthly.
display_name string yes
position integer yes Order in the offering, lowest first.
created_at integer yes Creation time. Epoch milliseconds.
products object no
products.object "list" yes
products.items array of PackageProduct yes
products.next_page string or null yes Path of the next page, or null on the last page.
products.url string yes Path of this list.

PackageProduct#

Field Type Required Description
product Product yes
eligibility_criteria all, google_sdk_lt_6, google_sdk_ge_6 yes

Product#

Field Type Required Description
object "product" yes
id string yes Product id (prod...).
store_identifier string yes The store's product id. Google Play subscriptions use subscriptionId:basePlanId; an App Store monthly billing plan (iOS 26.4) uses productId:monthly.
type subscription, one_time, consumable, non_consumable, non_renewing_subscription yes
state active, inactive yes
subscription object no
subscription.duration string or null no ISO 8601 period such as P1M.
subscription.grace_period_duration null no
subscription.trial_duration null no
one_time object no
one_time.is_consumable boolean or null no
created_at integer yes Creation time. Epoch milliseconds.
app_id string yes
display_name string or null yes
app App no Only the object for the app's own type is present. Store secrets are never returned.
indicative_price IndicativePrice or null no With expand=indicative_price: the Test Store price; else the App Store or Google Play price in the United States from the last store price read (or the in-app purchase's base territory, or the first territory with a price); else the Stripe web product's price. Null when none is known.
store_details StoreDetails or null no RevenueDot extension, with expand=store_details: the store's status and price from the last store price read. Null when the product was never read from App Store Connect or Google Play (other stores, or no read yet).

ProductPrice#

Field Type Required Description
id string or null yes Price id (prc...); null for a price saved before prices by currency existed, until it is changed. The Stripe price id for a web product.
currency string yes ISO 4217 code.
amount_micros integer yes Price in micros: 9.99 is 9990000.

Project#

Field Type Required Description
object "project" yes
id string yes Project id (proj...).
name string yes
created_at integer yes Creation time. Epoch milliseconds.
icon_url string or null no Always null.
icon_url_large string or null no Always null.

PublicApiKey#

Field Type Required Description
object "public_api_key" yes
id string yes
key string yes The key the SDK sends (appl_, goog_, test_ ...).
environment production, sandbox yes
app_id string yes
created_at integer yes Creation time. Epoch milliseconds.

Purchase#

Field Type Required Description
object "purchase" yes
id string yes
customer_id string yes
original_customer_id string no
product_id string yes
purchased_at integer yes Purchase time. Epoch milliseconds.
revenue_in_usd MonetaryAmount no
quantity integer no
status owned, refunded yes
presented_offering_id string or null no Offering the purchase was made from (its id, or the identifier the SDK sent when no such offering exists).
entitlements object no
entitlements.object "list" yes
entitlements.items array of Entitlement yes
entitlements.next_page string or null yes Path of the next page, or null on the last page.
entitlements.url string yes Path of this list.
environment production, sandbox yes
store string yes
store_purchase_identifier string no
ownership purchased no
country string no

StoreDetails#

Field Type Required Description
object "store_details" yes
status string or null yes The store's state in lower case: approved, ready_to_submit, waiting_for_review, in_review, rejected, developer_action_needed, missing_metadata, removed_from_sale (App Store), active, draft, inactive (Google Play).
store_state string or null yes The state as the store spells it, such as APPROVED or ACTIVE.
price object or null yes The United States price when the product has one, else the in-app purchase's base territory or the first territory with a price. Null when the store has no price for it.
territories integer yes How many territories have a price.
duration string or null yes The store's period for a subscription (P1M ...).
display_name string or null yes The name in the store.
editable boolean yes Whether the product editor can change its prices.
refreshed_at integer yes When the prices were read from the store. Epoch milliseconds.
refresh_status ok, failing, null yes The app's last read: failing means it failed and these values are from the read before.

StoreProductImport#

Field Type Required Description
object "store_product_import" yes
app_id string yes
created array of Product yes Products created by this import.
existing array of Product yes Requested products the catalog already had; left unchanged.
failed array of object yes Requested identifiers the store does not have, or that cannot be imported.
failed[].store_identifier string yes
failed[].reason not_in_store, not_importable yes
failed[].message string yes
entitlement_ids array of string yes The entitlements every created and existing product is attached to.

Subscription#

Field Type Required Description
object "subscription" yes
id string yes Subscription id (sub_...).
customer_id string yes
original_customer_id string no
product_id string or null no Product id (prod...), null for promotional grants.
starts_at integer yes Start of the subscription. Epoch milliseconds.
current_period_starts_at integer no Start of the current period. Epoch milliseconds.
current_period_ends_at integer or null no End of the current period. Epoch milliseconds, or null.
ends_at integer or null no End of access. Epoch milliseconds, or null.
gives_access boolean yes
pending_payment boolean no
auto_renewal_status will_renew, will_not_renew, will_change_product, will_pause yes
status trialing, active, in_grace_period, in_billing_retry, paused, expired yes
total_revenue_in_usd MonetaryAmount no
presented_offering_id string or null no Offering the purchase was made from (its id, or the identifier the SDK sent when no such offering exists).
entitlements object no
entitlements.object "list" yes
entitlements.items array of Entitlement yes
entitlements.next_page string or null yes Path of the next page, or null on the last page.
entitlements.url string yes Path of this list.
environment production, sandbox yes
store string yes
store_subscription_identifier string no Latest store transaction id, order id or token.
ownership purchased, family_shared no
country string no ISO 3166-1 alpha-2, when known.
management_url null no

SubscriptionTransaction#

Field Type Required Description
object "subscription_transaction" yes
id string yes
purchased_at integer yes Purchase time. Epoch milliseconds.
product_store_identifier string no
revenue_in_local_currency MonetaryAmount or null no
revenue_in_usd MonetaryAmount no
expiration_date integer or null no End of the period. Epoch milliseconds, or null.
effective_expiration_date integer or null no When access actually ended (the refund time for a refunded period). Epoch milliseconds, or null.

V2Error#

Field Type Required Description
object "error" yes
type parameter_error, resource_already_exists, resource_missing, idempotency_error, rate_limit_error, authentication_error, authorization_error, store_error, server_error, resource_locked_error, unprocessable_entity_error, invalid_request, entity_references_archived_entities, plan_required yes
message string yes What went wrong.
param string no The request field at fault, when there is one.
doc_url string yes Link to the error's section of the errors page.
retryable boolean yes True when retrying the same request can succeed.
upgrade_url string no Only on plan_required: the Billing page where the owner starts Pro.

WebhookIntegration#

Field Type Required Description
object "webhook_integration" yes
id string yes Webhook id (wh_...).
project_id string yes
name string yes
url string yes
environment production, sandbox, null yes Null sends both.
event_types array of string yes Lower-case event types. Empty sends every type.
app_id string or null yes Only events of this app, or null for all.
created_at integer yes Creation time. Epoch milliseconds.
signing_secret string no whsec_... Only in the answer that creates the webhook.