VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL

Teams, projects and environments

How Voidhash organizes your apps, and how test purchases stay apart from production.

A team is your company's account in Voidhash, and a project is one app or product inside it. A project owns its API keys, products, perks, paywalls, people and analytics. Inside a project, every purchase and event belongs to an environment: production, sandbox or test.

The API and the CLI's org command call a team an organization.

Create a team and a project

The first time you sign in, Studio asks for a team name (3 to 32 characters) and a first project (up to 32 characters, with its platforms). Add more projects from the project switcher. See Get around Studio for the walkthrough.

Give each app its own project, and keep the iOS, Android and web versions of one app in the same project, so one person's access and analytics cover every platform.

Project settings

Under Settings → General, Studio shows the Project ID the API and CLI use, and holds:

  • Simulated purchases: lets debug builds in development mode buy without a store. It is on for new projects. Deleting simulated purchases leaves production, sandbox, Stripe test mode and payment source test purchases in place.
  • Tracking domain: a first-party domain for the web SDK, on Voidhash Cloud only. See Tracking domain.
  • Delete project: deletes the project and all of its data, for admins and owners only.
Deleting a project can't be undone

Deleting a project permanently deletes all of its data. To confirm, you type the project's team/project path.

Three settings are not in Studio. Change them with PATCH /api/v1/projects/{projectId}/settings, the MCP tool update_project_settings, or the CLI (voidhash settings set):

API field (CLI key)ValuesDefaultWhat it controls
storeSandbox.isUnlockingProduction (store-sandbox-unlocks-production)true, false (on, off)trueWhether store sandbox purchases unlock access in production apps. See Store sandbox in production apps.
paidAccessSharing.production (paid-access-sharing.production)shared, transfer, disabledtransferWhat happens when someone restores a purchase that another account of your app made.
paidAccessSharing.sandbox (paid-access-sharing.sandbox)shared, transfer, disabledtransferThe same, for store sandbox and test purchases.

The paid access sharing modes:

  • shared: both people keep access.
  • transfer: access moves to the person who restored the purchase.
  • disabled: access stays with the person who bought it.

A change applies to purchases reported from then on. The CLI asks for confirmation before it changes a setting that affects production apps.

curl -X PATCH "https://api.voidhash.com/api/v1/projects/$VOIDHASH_PROJECT_ID/settings" \
  -H "Authorization: Bearer $VOIDHASH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"storeSandbox": {"isUnlockingProduction": false}}'
voidhash settings set store-sandbox-unlocks-production off

Environments

EnvironmentWhat it holds
productionReal purchases from the App Store, Google Play, Stripe live mode and payment sources.
sandboxFree purchases made in a store's own sandbox: App Store sandbox accounts, TestFlight, App Review and Google Play test purchases.
testFree purchases from your own builds and servers: simulated purchases in development mode, Stripe test mode, and payment sources reporting with a test key.

The key a request uses decides the environment it reads and writes. Every API key belongs to production or test for its whole life:

KeyReadsRecords events and reports as
Production (vh_pk_…, vh_sk_…)Production purchases, plus store sandbox purchases while they unlock production appsproduction
Test (vh_pk_test_…, vh_sk_test_…)Store sandbox and test purchasestest

No request header changes what a key reads. See API keys for how to create and use each key.

Store sandbox in production apps

The store, not your app, decides whether a purchase is a sandbox one. TestFlight runs the build you ship, and App Review buys with a sandbox account in the build you submit. So by default, store sandbox purchases unlock access in apps that use the production key, and App Review can open what it buys.

Set storeSandbox.isUnlockingProduction to false to stop this (in the MCP tool, storeSandboxUnlocksProduction; in the CLI, store-sandbox-unlocks-production off). App Review then no longer unlocks what it buys, and TestFlight testers need a build with the test publishable key. Test purchases never unlock production, whatever this setting says.

Development mode

Development mode lets a debug build buy from a simulated store, for example on an emulator. It is available in the Swift, Kotlin and React Native SDKs. Debug builds in development mode must use the test publishable key: Voidhash refuses simulated purchases made with a production key. Their purchases are recorded as test.

Simulated purchases need Enable simulated purchases on under Settings → General → Simulated purchases, which it is by default (voidhash settings set sandbox-purchasing on). Voidhash processes them for real, so perks, webhooks and analytics behave as in production.

Simulate renewals, expiry and refunds

Move a person's simulated purchases through their lifecycle without waiting for a store. Each action changes the person's access at once; webhooks and analytics follow in the background.

ActionApplies toEffect
renewSubscriptionRenews it for another period.
expireSubscriptionEnds it now.
grace_periodSubscriptionStarts a 3-day billing grace period, as after a failed renewal.
refundOne-time purchaseRefunds it; its access ends.
revokeEitherRevokes it, as when the store takes it back.

Ask your agent, for example "Renew user_123's simulated pro_monthly subscription". It uses get_sandbox_purchases to find the purchase, simulate_sandbox_event to play the action and reset_sandbox to start over. See People tools.

Read the person's simulated purchases to get the subscription or purchase ID, then post an action with a secret key. Repeating an actionId applies the action once.

curl "https://api.voidhash.com/api/v1/projects/$PROJECT_ID/sandbox/state?personId=$PERSON_ID" \
  -H "Authorization: Bearer $VOIDHASH_SECRET_KEY"

curl -X POST "https://api.voidhash.com/api/v1/projects/$PROJECT_ID/sandbox/actions" \
  -H "Authorization: Bearer $VOIDHASH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "actionId": "renew-1", "action": "renew", "targetType": "subscription", "targetId": "sub_..." }'

DELETE /api/v1/projects/{projectId}/sandbox/data deletes every simulated purchase.

voidhash sandbox view user_123
voidhash sandbox renew user_123 pro_monthly
voidhash sandbox grace-period user_123
voidhash sandbox reset

reset asks first; --yes skips that. Name the product when the person has several. The CLI isn't published yet; see Install the CLI.

Delete simulated purchases under Settings → General also resets them. Resetting never touches production, store sandbox, Stripe test mode or payment-source test purchases, and the actions work only on simulated purchases: store sandbox and Stripe test purchases follow their store.

Analytics and webhooks

Voidhash stamps every analytics event with the environment of the key that sent it. Revenue events take the environment of their purchase. A staging website on the test key therefore stays out of your production visitors, events and experiment results.

People are not split by environment. If staging identifies users with the same IDs as production, both reach the same people, so give staging users IDs of their own, such as a staging: prefix.

Webhook endpoints also belong to production or test; see Environments.

Switch environments in Studio

Studio shows one environment at a time. Open the project switcher and choose Production, Sandbox or Test. Purchases and revenue follow the switch. The Production and Sandbox views show production events, since store sandbox purchases come from apps that use the production key; Test shows test events.

A typical setup

Where it runsKeyWebhook endpoint
App Store and Google Play release builds, including TestFlight and Play test tracksProduction publishable key—
Production website and backendProduction publishable and secret keysProduction
Staging website and backend, Stripe test modeTest publishable and secret keysTest
Debug builds in development modeTest publishable keyTest

Next steps

  • Create and manage API keys
  • Create products and perks
  • Test purchases on every platform (Help center)

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousVersions and releasesNextAPI keys

On this page

Create a team and a projectProject settingsEnvironmentsStore sandbox in production appsDevelopment modeSimulate renewals, expiry and refundsAnalytics and webhooksSwitch environments in StudioA typical setupNext steps