=============== LIBRARY RULES =============== From library maintainers: - RevenueDot works with the RevenueCat SDK: set the SDK's proxy URL to https://api.revenuedot.app (RevenueDot Cloud) or to your own server, and keep your purchase code. - The SDKs are RevenueDot's MIT forks of RevenueCat's SDKs; imports and class names stay the same (for example `import RevenueCat` on iOS and `com.revenuecat.purchases.*` on Android). Each SDK has a guide in docs/sdks. - Self-host with Docker and Postgres using the guide docs/guides/self-hosting.md; RevenueDot Cloud is at https://app.revenuedot.app. - The REST API reference is generated from api/openapi.yaml (OpenAPI 3.1); the same API is served by Cloud and self-hosted servers. - To move an app off RevenueCat, follow docs/migrate/README.md: import, run side by side, then switch the proxy URL. ### Run purchases-js web example with Test Store Source: https://github.com/revenuedot/docs/blob/main/docs/getting-started/quickstart.md Run the purchases-js web example in a browser. Clones the examples repo, installs dependencies, writes the proxy URL and Test Store API key to .env.local, then starts the dev server at http://localhost:5199. Click Buy and then "Test valid purchase" to see the SDK in action. ```bash git clone https://github.com/revenuedot/examples.git && cd examples/web/purchases-js-vite npm install printf "VITE_REVENUEDOT_URL=https://api.revenuedot.app\nVITE_REVENUEDOT_API_KEY=test_...\n" > .env.local npm run dev # open http://localhost:5199, click Buy, then "Test valid purchase" ``` -------------------------------- ### GET /sso/start Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Starts a sign-in for an email address. No authentication required. Redirects to the identity provider or to /login?sso_error=... on failure. Rate limited to 30 starts per minute per IP address. ```bash curl -s "$REVENUEDOT_URL/sso/start" ``` -------------------------------- ### GET /v2/enterprise - Example 200 response Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Example 200 response for GET /v2/enterprise showing a development-mode licence with the full feature set and a warning message. ```json { "object": "enterprise", "mode": "development", "features": [ "organizations", "custom_roles", "sso", "scim", "data_location", "audit_retention", "compliance_exports" ], "licensee": null, "expires_at": null, "message": "Development mode: for development and testing only, not for production (ee/LICENSE)." } ``` -------------------------------- ### GET /sso/connections/{id}/start Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Starts a sign-in with a specific connection using its start_url. No authentication required. Redirects to the identity provider or to /login?sso_error=... on failure. ```bash curl -s "$REVENUEDOT_URL/sso/connections/$ID/start" ``` -------------------------------- ### Install RevenueDot Unity SDK via OpenUPM Source: https://github.com/revenuedot/docs/blob/main/docs/sdks/unity.md Adds the RevenueDot fork package using the OpenUPM CLI. Requires OpenUPM to be installed. ```bash openupm add com.revenuedot.purchases-unity ``` -------------------------------- ### GET /sso/start Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Starts a sign-in for an email address. Opens in the browser. Finds the organization that verified the address's domain and sends the browser to its first enabled connection (oldest first). ```APIDOC ## GET /sso/start ### Description Starts a sign-in for an email address. Opens in the browser. Finds the organization that verified the address's domain and sends the browser to its first enabled connection (oldest first). At most 30 starts a minute per IP address. Failures redirect to `/login?sso_error=`. ### Method GET ### Endpoint /sso/start ### Parameters #### Query Parameters - **email** (string) - Required - The work email address. - **next** (string) - Optional - A path on this site to open after sign-in. Anything else becomes `/`. ### Request Example ```bash curl -s "$REVENUEDOT_URL/sso/start" ``` ### Response #### Success Response (303) To the identity provider, or to `/login?sso_error=...`. ``` -------------------------------- ### GET /sso/connections/{id}/start Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Starts a sign-in with one connection. This is the `start_url` of a connection. Failures redirect to `/login?sso_error=`. ```APIDOC ## GET /sso/connections/{id}/start ### Description Starts a sign-in with one connection. This is the `start_url` of a connection. Failures redirect to `/login?sso_error=`. ### Method GET ### Endpoint /sso/connections/{id}/start ### Parameters #### Path Parameters - **id** (string) - Required - Connection id (ssoc_...). #### Query Parameters - **next** (string) - Optional - A path on this site to open after sign-in. ### Request Example ```bash curl -s "$REVENUEDOT_URL/sso/connections/$ID/start" ``` ### Response #### Success Response (303) To the identity provider, or to `/login?sso_error=...`. ``` -------------------------------- ### Set up Test Store app and product with curl Source: https://github.com/revenuedot/docs/blob/main/docs/guides/test-store.md Creates a Test Store app, fetches its public API key (the test_ key), and creates a subscription product with a P1M duration. Requires REVENUEDOT_URL, PROJECT_ID, SECRET_KEY, and APP_ID environment variables. ```bash B="$REVENUEDOT_URL/v2/projects/$PROJECT_ID"; H="Authorization: Bearer $SECRET_KEY" curl -s -X POST "$B/apps" -H "$H" -H "Content-Type: application/json" -d '{"name":"Test Store","type":"test_store"}' curl -s "$B/apps/$APP_ID/public_api_keys" -H "$H" # -> "key": "test_..." curl -s -X POST "$B/products" -H "$H" -H "Content-Type: application/json" \ -d '{"store_identifier":"pro_monthly","app_id":"'$APP_ID'","type":"subscription","display_name":"Pro monthly","subscription":{"duration":"P1M"}}' ``` -------------------------------- ### GET /v2/organizations - Example 200 response Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Example 200 response for GET /v2/organizations showing a list with one organization and its details. ```json { "object": "list", "items": [ { "object": "organization", "id": "org_k2m9q4x7z1a8", "name": "Acme Inc.", "your_role": "owner", "region": "us", "region_name": "United States", "selectable_regions": [ "us", "eu" ], "region_enforced": false, "audit_retention_days": 365, "sso_enforced": true, "seats": { "purchased": 50, "used": 23 }, "billing_email": "finance@acme.com", "member_count": 23, "project_count": 3, "features": [ "organizations", "custom_roles", "sso", "scim", "data_location", "audit_retention", "compliance_exports" ], "created_at": 1790800914012, "updated_at": 1790887314012 } ], "next_page": null, "url": "/v2/organizations" } ``` -------------------------------- ### POST /v2/projects/{project_id}/experiments/{experiment_id}/actions/start Source: https://github.com/revenuedot/docs/blob/main/docs/guides/experiments.md Starts the specified experiment. ```APIDOC ## POST /v2/projects/{project_id}/experiments/{experiment_id}/actions/start ### Description Start an experiment. ### Method POST ### Endpoint /v2/projects/{project_id}/experiments/{experiment_id}/actions/start ### Parameters #### Path Parameters - **project_id** (string) - Required - The project identifier. - **experiment_id** (string) - Required - The experiment identifier. ### Response #### Success Response (200) - **status** (string) - Action status. ``` -------------------------------- ### Example 200 response for Get a user Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Example 200 response for the Get a user request. Shows the ScimUser structure with schemas, id, externalId, userName, name, emails, active, groups, and meta fields. ```json { "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:User" ], "id": "scu_9x2k4m8q1z7a3b5c", "externalId": "00u1a2b3c4d5", "userName": "sam@acme.com", "name": { "givenName": "Sam", "familyName": "Lee" }, "emails": [ { "value": "sam@acme.com", "type": "work", "primary": true } ], "active": true, "groups": [ { "value": "scg_4k8m2q9x1z7a3b5c", "display": "RevenueDot Support" } ], "meta": { "resourceType": "User", "created": "2026-10-01T09:12:00.000Z", "lastModified": "2026-10-01T09:12:00.000Z", "location": "https://app.revenuedot.app/scim/v2/Users/scu_9x2k4m8q1z7a3b5c", "version": "W/\"1\"" } } ``` -------------------------------- ### Intro eligibility 200 response Source: https://github.com/revenuedot/docs/blob/main/api/sdk-endpoints.md Example 200 response for the intro eligibility endpoint. Shows that the eligibility for each product is null, meaning the SDK must determine eligibility locally. ```json { "pro_monthly": null } ``` -------------------------------- ### Offerings response example Source: https://github.com/revenuedot/docs/blob/main/api/sdk-endpoints.md Example 200 response for the get offerings endpoint. Shows the structure of the offerings object with packages. ```json { "current_offering_id": "default", "offerings": [ { "description": "Standard plans", "identifier": "default", "metadata": null, "packages": [ { "identifier": "$rc_monthly", "platform_product_identifier": "pro_monthly" }, { "identifier": "$rc_annual", "platform_product_identifier": "pro_annual" }, { "identifier": "$rc_lifetime", "platform_product_identifier": "pro_lifetime" } ] } ] } ``` -------------------------------- ### List groups with GET /scim/v2/Groups Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Lists groups with a GET request to /scim/v2/Groups. The example shows a 200 response with a ListResponse containing one Group resource. ```bash curl -s "$REVENUEDOT_URL/scim/v2/Groups" -H "Authorization: Bearer $SCIM_TOKEN" ``` ```json { "schemas": [ "urn:ietf:params:scim:api:messages:2.0:ListResponse" ], "totalResults": 1, "startIndex": 1, "itemsPerPage": 1, "Resources": [ { "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:Group" ], "id": "scg_4k8m2q9x1z7a3b5c", "displayName": "RevenueDot Support", "members": [ { "value": "scu_9x2k4m8q1z7a3b5c", "display": "Sam Lee", "type": "User" } ], "meta": { "resourceType": "Group", "created": "2026-10-01T09:12:00.000Z", "lastModified": "2026-10-01T09:12:00.000Z", "location": "https://app.revenuedot.app/scim/v2/Groups/scg_4k8m2q9x1z7a3b5c", "version": "W/\"1\"" } } ] } ``` -------------------------------- ### Install and run build/check scripts Source: https://github.com/revenuedot/docs/blob/main/README.md Install dependencies and run the build and check scripts. Requires Node.js 20+ (CI uses 24); the drift check needs a checkout of revenuedot/revenuedot next to this repo or the REVENUEDOT_SERVER_DIR environment variable. ```bash npm install npm run build # api/openapi.yaml, api/*.md, llms.txt, llms/, llms-full.txt npm run check # OpenAPI validation, drift against the server code, page frontmatter, links and anchors ``` -------------------------------- ### GET /v2/enterprise Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Retrieves the license state and features of the RevenueDot Enterprise installation. ```APIDOC ## GET /v2/enterprise ### Description Retrieves the license state and features of the RevenueDot Enterprise installation. ### Method GET ### Endpoint /v2/enterprise ### Authentication Dashboard session ### Parameters None ### Request Example ```bash curl -s "$REVENUEDOT_URL/v2/enterprise" ``` ### Response #### Success Response (200) Returns the license state. Returns [EnterpriseStatus](#enterprisestatus). #### Response Example ```json { "object": "enterprise", "mode": "development", "features": [ "organizations", "custom_roles", "sso", "scim", "data_location", "audit_retention", "compliance_exports" ], "licensee": null, "expires_at": null, "message": "Development mode: for development and testing only, not for production (ee/LICENSE)." } ``` #### Error Responses - **401**: No API key, or an unknown one. Returns [V2Error](#v2error). ``` -------------------------------- ### Initialize and apply Terraform for AWS deployment Source: https://github.com/revenuedot/docs/blob/main/docs/guides/high-availability.md Copy the example Terraform variables file and run Terraform init, plan, and apply to create the infrastructure. The variables file includes domain_name, route53_zone_id, image, and alarm_email. ```bash cd deploy/terraform/aws cp terraform.tfvars.example terraform.tfvars # domain_name, route53_zone_id, image, alarm_email terraform init && terraform plan && terraform apply ``` -------------------------------- ### Get a group 200 response Source: https://github.com/revenuedot/docs/blob/main/api/enterprise.md Example 200 response for the Get a group request. Shows the ScimGroup structure with schemas, id, displayName, members, and meta fields. ```json { "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:Group" ], "id": "scg_4k8m2q9x1z7a3b5c", "displayName": "RevenueDot Support", "members": [ { "value": "scu_9x2k4m8q1z7a3b5c", "display": "Sam Lee", "type": "User" } ], "meta": { "resourceType": "Group", "created": "2026-10-01T09:12:00.000Z", "lastModified": "2026-10-01T09:12:00.000Z", "location": "https://app.revenuedot.app/scim/v2/Groups/scg_4k8m2q9x1z7a3b5c", "version": "W/\"1\"" } } ``` -------------------------------- ### GET /v2/enterprise response for licensed self-hosted server Source: https://github.com/revenuedot/docs/blob/main/docs/guides/enterprise.md Example response from GET /v2/enterprise on a self-hosted server with a valid licence key. Shows mode 'licensed' and the full feature list. ```json { "object": "enterprise", "mode": "licensed", "features": ["organizations", "custom_roles", "sso", "scim", "data_location", "audit_retention", "compliance_exports"], "licensee": "Acme Inc.", "expires_at": 1822348800000, "message": null } ``` -------------------------------- ### Kubernetes Helm installation commands Source: https://github.com/revenuedot/docs/blob/main/docs/guides/high-availability.md Creates a namespace, secrets for the database URL and server secrets, installs the Helm chart, and checks the rollout status and runs Helm tests. ```bash kubectl create namespace revenuedot kubectl -n revenuedot create secret generic revenuedot-db \ --from-literal=DATABASE_URL='postgres://revenuedot:@:5432/revenuedot?sslmode=require' kubectl -n revenuedot create secret generic revenuedot-secrets \ --from-literal=REVENUEDOT_ENCRYPTION_KEY="$(openssl rand -base64 32)" \ --from-literal=REVENUEDOT_SMTP_URL='smtps://:@smtp.example.com:465' helm install revenuedot deploy/helm/revenuedot -n revenuedot \ --set image.repository=/revenuedot --set image.tag= \ --set publicUrl=https://revenuedot.example.com \ --set database.existingSecret=revenuedot-db --set secrets.existingSecret=revenuedot-secrets \ --set ingress.enabled=true --set ingress.className=nginx \ --set ingress.hosts[0].host=revenuedot.example.com \ --set ingress.hosts[0].paths[0].path=/ --set ingress.hosts[0].paths[0].pathType=Prefix kubectl -n revenuedot rollout status deploy/revenuedot && helm test revenuedot -n revenuedot ``` -------------------------------- ### POST /v1/subscribers/{app_user_id}/intro_eligibility Source: https://github.com/revenuedot/docs/blob/main/api/sdk-endpoints.md Calls the intro offer eligibility endpoint. The SDK uses this to check eligibility for introductory offers, but RevenueDot always returns null for each product, so the SDK decides eligibility on the device. ```bash curl -s -X POST "$REVENUEDOT_URL/v1/subscribers/user_1/intro_eligibility" -H "Authorization: Bearer $PUBLIC_KEY" ``` -------------------------------- ### EXPERIMENT_ENROLLMENT webhook event example Source: https://github.com/revenuedot/docs/blob/main/api/webhook-events.md Example webhook payload for the EXPERIMENT_ENROLLMENT event. Sent once per customer and experiment, as a production event with no app, so a webhook set to sandbox only or to one app does not get it. ```json { "api_version": "1.0", "event": { "event_timestamp_ms": 1790800914012, "app_user_id": "$RCAnonymousID:12345678123412341234123456789123", "aliases": [ "$RCAnonymousID:12345678123412341234123456789123" ], "original_app_user_id": "$RCAnonymousID:12345678123412341234123456789123", "experiment_id": "prexpca1234ab", "experiment_variant": "b", "offering_id": "promo", "experiment_enrolled_at_ms": 1790800914012, "type": "EXPERIMENT_ENROLLMENT", "id": "0F1E2D3C-4B5A-4978-8695-A4B3C2D1E0F9" } } ``` -------------------------------- ### VIRTUAL_CURRENCY_TRANSACTION webhook event example Source: https://github.com/revenuedot/docs/blob/main/api/webhook-events.md Example webhook event for an in-app currency credit from a purchase of a granting product (`source: in_app_purchase`). Shows the `adjustments` array, `virtual_currency_transaction_id` starting with `vatx`, and subscriber attributes. ```json { "api_version": "1.0", "event": { "adjustments": [ { "amount": 100, "currency": { "code": "GLD", "description": "Gold coins", "name": "Gold" } } ], "aliases": [ "$RCAnonymousID:8069238d6049ce87cc529853916d624c" ], "app_id": "appe8dyp6dl", "app_user_id": "user_1", "event_timestamp_ms": 1790800914012, "product_display_name": "100 coins", "product_id": "coins_100", "purchase_environment": "PRODUCTION", "source": "in_app_purchase", "store": "APP_STORE", "subscriber_attributes": { "$email": { "updated_at_ms": 1790800900000, "value": "ana@example.com" } }, "transaction_id": "2000000123456789", "virtual_currency_transaction_id": "vatx1a2b3c4d5e6f7g", "type": "VIRTUAL_CURRENCY_TRANSACTION", "id": "8F2B1C4D-1234-4C5D-9E6F-0A1B2C3D4E5F" } } ``` -------------------------------- ### GET /v2/enterprise response for RevenueDot Cloud Source: https://github.com/revenuedot/docs/blob/main/docs/guides/enterprise.md Example response from GET /v2/enterprise on RevenueDot Cloud. Shows mode 'cloud', the account's plan, and the features that plan has, with locked features listed for higher plans. ```json { "object": "enterprise", "mode": "cloud", "plan": "standard", "features": ["organizations", "custom_roles", "sso"], "locked": [{ "feature": "scim", "plan": "enterprise" }, { "feature": "data_location", "plan": "enterprise" }, { "feature": "audit_retention", "plan": "enterprise" }, { "feature": "compliance_exports", "plan": "enterprise" }], "licensee": null, "expires_at": null, "message": null } ``` -------------------------------- ### Win-back offers response example Source: https://github.com/revenuedot/docs/blob/main/docs/guides/win-back-offers.md Example JSON response from the win-back offers endpoint. It includes a list of eligibility objects with subscription and product IDs, store, offer IDs, and a timestamp. The 'offer_ids' field is empty when Apple offers nothing. ```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" } ``` -------------------------------- ### Get Test Store product details Source: https://github.com/revenuedot/docs/blob/main/api/sdk-endpoints.md Fetches product details for Test Store and web products. Requires a public app key. Prices are 0 until the catalog stores Test Store prices. ```bash curl -s "$REVENUEDOT_URL/rcbilling/v1/subscribers/user_1/products" -H "Authorization: Bearer $PUBLIC_KEY" ``` -------------------------------- ### Build an offering with curl Source: https://github.com/revenuedot/docs/blob/main/docs/concepts/offerings-and-packages.md Creates an offering, adds a package with the standard $rc_monthly lookup key, and attaches one product per app. The first offering becomes current; package order follows position then creation time. Two products of the same app can share a package only when eligibility_criteria do not overlap, otherwise the API returns 409. ```bash B="$REVENUEDOT_URL/v2/projects/$PROJECT_ID"; H="Authorization: Bearer $SECRET_KEY" # 1. The offering. The project's first offering becomes current. curl -s -X POST "$B/offerings" -H "$H" -H "Content-Type: application/json" -d '{"lookup_key":"default","display_name":"Standard plans"}' # 2. A package, placed first. curl -s -X POST "$B/offerings/$OFFERING_ID/packages" -H "$H" -H "Content-Type: application/json" -d '{"lookup_key":"$rc_monthly","display_name":"Monthly","position":0}' # 3. One product per app in the package. curl -s -X POST "$B/packages/$PACKAGE_ID/actions/attach_products" -H "$H" -H "Content-Type: application/json" \ -d '{"products":[{"product_id":"'$IOS_MONTHLY'","eligibility_criteria":"all"},{"product_id":"'$ANDROID_MONTHLY'","eligibility_criteria":"all"}]}' ``` -------------------------------- ### Get customer info (GET /v1/subscribers/{app_user_id}) Source: https://github.com/revenuedot/docs/blob/main/api/sdk-endpoints.md Gets customer info for a given app user id. This is what Purchases.getCustomerInfo() calls. Creates the customer when the app user id is new (answer 201). With a secret key the answer also has subscriber_attributes. Entitlements are listed even after they expire; an entitlement is active while expires_date is null or in the future. The example uses a public app key. ```bash curl -s "$REVENUEDOT_URL/v1/subscribers/user_1" -H "Authorization: Bearer $PUBLIC_KEY" ``` ```json { "request_date": "2026-09-30T20:41:54Z", "request_date_ms": 1790800914034, "subscriber": { "entitlements": { "pro": { "expires_date": "2026-10-30T20:41:54Z", "grace_period_expires_date": null, "product_identifier": "pro_monthly", "purchase_date": "2026-09-30T20:41:54Z" } }, "first_seen": "2026-09-30T20:41:54Z", "last_seen": "2026-09-30T20:41:54Z", "management_url": null, "non_subscriptions": {}, "original_app_user_id": "user_1", "original_application_version": null, "original_purchase_date": "2026-09-30T20:41:54Z", "other_purchases": {}, "subscriptions": { "pro_monthly": { "auto_resume_date": null, "billing_issues_detected_at": null, "display_name": null, "expires_date": "2026-10-30T20:41:54Z", "grace_period_expires_date": null, "is_sandbox": true, "management_url": null, "original_purchase_date": "2026-09-30T20:41:54Z", "ownership_type": "PURCHASED", "period_type": "normal", "purchase_date": "2026-09-30T20:41:54Z", "refunded_at": null, "store": "test_store", "store_transaction_id": "test_1790800914000_quickstart", "unsubscribe_detected_at": null, "price": { "amount": 9.99, "currency": "USD" } } } } } ``` -------------------------------- ### Import report output example Source: https://github.com/revenuedot/docs/blob/main/docs/migrate/importer.md Example report output from the import command. Problem sections are Store credentials to re-enter, Skipped, Errors and Notes; each shows 50 lines, with the full list in the state file. --json prints everything. ```text Import finished: RevenueCat project proj1ab2c3d4 -> https://revenuedot.example.com (project projujvzn2wl). Catalog Apps 2 created, 0 already there Products 6 created, 0 already there Entitlements 1 created, 0 already there Offerings 2 created, 0 already there Packages 4 created, 0 already there SDK keys 2 kept (existing app builds keep working with RevenueDot) Customers (pass 1, complete) 1200 customers imported (1180 new, 20 merged with existing ones) 950 subscriptions, 130 one-time purchases 310 Google Play subscriptions need a purchase token (add the service account and run again; see "revenuedot import plan") Store credentials to re-enter in RevenueDot (they cannot be exported) - ... ``` -------------------------------- ### POST /rcbilling/v1/checkout/start (not available) Source: https://github.com/revenuedot/docs/blob/main/api/sdk-endpoints.md Start a Web Billing checkout, not available. Returns 400. Requires a public app key. ```bash curl -s -X POST "$REVENUEDOT_URL/rcbilling/v1/checkout/start" -H "Authorization: Bearer $PUBLIC_KEY" ```