# Create claimable sandboxes Learn how to create anonymous, claimable sandboxes to allow users to build a Stripe integration Claimable sandboxes are anonymous [sandboxes](https://docs.stripe.com/sandboxes.md) that aren’t initially owned by an existing account. You can programmatically create claimable sandboxes for your users with the Claimable Sandboxes API and populate each sandbox with data to help your users get started. When users are ready to take ownership of a sandbox and make projects live, they can claim the sandbox by visiting its onboarding URL. On that page, they can create a new Stripe account to associate with the sandbox or choose an existing Stripe account to move the sandbox into that account. ## Build a claimable sandbox integration In this guide, you’ll integrate the Claimable Sandboxes API into a fictional agent-assisted coding platform called Bizbot and work with the following entities: - Bizbot: An agent-assisted coding platform - `com.bizbot.app`: The Stripe App that uses the Claimable Sandboxes API - Jenny Rosen: An end user of Bizbot ## Create a Stripe App To use the Claimable Sandboxes API to create claimable sandboxes, you must first create a *Stripe App* (An app that you can build on top of Stripe to customize the functionality of the Stripe Dashboard UI, leverage Stripe user data, store data on Stripe, and more). This allows your platform to act on the sandbox on behalf of your end user and access sandbox data. To get started, [create a Stripe App](https://docs.stripe.com/stripe-apps/create-app.md). Include these settings in the [manifest](https://docs.stripe.com/stripe-apps/reference/app-manifest.md) file and set the public distribution type for your new Stripe app. > Stripe doesn’t support public distribution on Connect platforms, so this feature doesn’t support Connect platforms. ```json { "stripe_api_access_type": "platform", "distribution_type": "public", "sandbox_install_compatible": true, "permissions": [ { "permission": "event_read", "purpose": "Allows [YOUR APP] access to read events." } ] } ``` Your app can request [permissions](https://docs.stripe.com/stripe-apps/reference/permissions.md) to operate on the sandbox. Request only the permissions required for the functionality you provide. For example, showing a list of subscriptions requires the `subscription_read` permission. When you upload your app to your account, Stripe automatically creates a [managed app sandbox](https://docs.stripe.com/stripe-apps/enable-sandbox-support.md#managed-sandbox) with the same name as your app ID. In the Bizbot example, the app ID might be `com.bizbot.app`. The following diagram shows the account structure. This diagram shows a live mode account of the Bizbot account with the managed app sandbox as a child node. (See full diagram at https://docs.stripe.com/sandboxes/claimable-sandboxes) After you create the app, send your app ID to [claimable_sandbox_preview@stripe.com](mailto:claimable_sandbox_preview@stripe.com). This lets Stripe: - Grant trusted access to the Claimable Sandboxes API - Keep the app unlisted in the Stripe Apps Marketplace - Complete the app review Make sure that you also set up an [external testing channel](https://docs.stripe.com/stripe-apps/test-app.md#set-up-test) for your app. This lets you test the API without first publishing your app. You must still [publish your app](https://docs.stripe.com/stripe-apps/publish-app.md) and have Stripe approve it before you can launch your integration to end users. For more information, see [Testing new app versions](https://docs.stripe.com/sandboxes/claimable-sandboxes.md#testing-new-app-versions). ## Call the Claimable Sandbox API Use the secret key from your managed app sandbox account to create claimable sandboxes. ```curl curl -X POST https://api.stripe.com/v2/core/claimable_sandboxes \ -H "Authorization: Bearer {{STRIPE_APP_SANDBOX_SECRET_KEY}}" \ -H "Stripe-Version: 2026-04-22.preview" \ --json '{ "app_channel": "public", "enable_mcp_access": true, "onboarding_link_details": { "refresh_url": "https://example.com/refresh" }, "prefill": { "email": "jenny.rosen@stripe.com", "name": "Jenny Sandbox", "country": "US" } }' ``` Use these parameters when you create a claimable sandbox. | Parameter | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `app_channel` | An enum with the values `public` or `testing`. When you launch this feature to your users, use `public`. For more information, see [Testing new app versions](https://docs.stripe.com/sandboxes/claimable-sandboxes.md#testing-new-app-versions). | | `enable_mcp_access` | Set this parameter to `true` to prompt Stripe to send you an API key that you can use to communicate with the [Stripe MCP](https://docs.stripe.com/mcp.md) server. This allows a large language model (LLM) to securely operate on your users’ Stripe accounts. | | `onboarding_link_details` | A hash that lets you specify the `refresh_url` that your end user is redirected to if they access an expired onboarding link. This parameter is required when you create a new claimable sandbox. The `refresh_url` must call a method on your server that invokes the Claimable Sandboxes Renew Onboarding Link API to renew the onboarding link expiration. | | `prefill` | A hash that lets you prefill values that your user provides when claiming the sandbox. For example, you can set `name` to your user’s project name. | Here’s what the API response looks like after you create a claimable sandbox: ```json { "id": "clmsbx_test_123", "object": "v2.core.claimable_sandbox", "app_channel": "public", "claimed_at": null, "created": "2026-04-22T00:00:00.000Z", "expires_at": "2026-06-21T00:00:00.000Z", "onboarding_link_details": { "expires_at": "2026-04-29T00:00:00.000Z", "refresh_url": "https://example.com/refresh", "url": "https://dashboard.stripe.com/onboard_sandbox/{{SIGNATURE}}" }, "owner_details": null, "prefill": { "email": "jenny.rosen@stripe.com", "name": "Jenny Sandbox", "country": "US" }, "sandbox_details": { "account": "acct_jenny_sandbox", "api_keys": { "publishable": "pk_test_123......", "secret": "sk_test_123.....", "mcp": "ek_test_123....." } }, "status": "unclaimed" } ``` ### Sandbox and onboarding link expiry A claimable sandbox expires after 60 days. You can see the exact expiration timestamp in the top-level `expires_at` field. Seven days before expiration, Stripe sends an email to the address in `prefill.email` to remind users to claim the account before Stripe deletes it. If a user doesn’t claim the sandbox within 60 days, Stripe permanently deletes it. The onboarding link is valid for seven days. You can see the exact expiration timestamp in the `onboarding_link_details.expires_at` field. If a user accesses an expired onboarding link, Stripe redirects the user to the URL in `onboarding_link_details.refresh_url`. Your `refresh_url` must call a method on your server that invokes the Claimable Sandboxes Renew Onboarding Link API, which renews the link for another seven days. ### Use API keys and authentication The keys and authentication method that you use depend on the entity performing the action: - LLM agents that act on behalf of the user must use [MCP tools](https://docs.stripe.com/mcp.md#tools) with the MCP key. - Deterministic code in your platform, for example code that retrieves payment data to build a dashboard that lists payments, must [call APIs](https://docs.stripe.com/stripe-apps/build-backend.md#using-stripe-apis) on the sandbox using [Stripe Apps authentication](https://docs.stripe.com/stripe-apps/build-backend.md#authenticate-requests). Stripe limits access to the permissions that you originally requested in your manifest. - The API response returns the `publishable` and `secret` keys for your platform to populate the end user’s application, for example through an `.env` file. When an end user of a generated application creates a payment, those API calls use the `secret` and `publishable` keys. Save the API keys from the create response because Stripe doesn’t return them in subsequent retrieve requests. > This MCP key expires seven days after a user claims the sandbox. Follow the [spec](https://modelcontextprotocol.io/specification/draft/basic/authorization) to make sure your platform can handle expired keys. When you create a new claimable sandbox, Stripe automatically pre-installs your platform’s Stripe App in that sandbox. This creates a connection between your platform and the sandbox and lets you perform actions on behalf of your users in the sandbox. The account structure now looks like this: This diagram shows that the managed app sandbox of Bizbot has a connection to the unclaimed sandbox for Jenny Rosen, which is created via the preinstalled Stripe App (See full diagram at https://docs.stripe.com/sandboxes/claimable-sandboxes) In the Bizbot example, because the Bizbot app is preinstalled in the sandbox account `acct_jenny_livemode`, the Bizbot managed app sandbox account `acct_bizbot_livemode` can now call APIs and listen for events from `acct_jenny_livemode`. To learn more, see [How Stripe Apps work](https://docs.stripe.com/stripe-apps/how-stripe-apps-work.md). ## Claim the sandbox When your user is ready to claim the account, your platform must provide the onboarding URL so the user can claim the sandbox in the Stripe Dashboard. If the user already has a Stripe account, they can claim the sandbox into that existing account. If the user doesn’t have an account, Stripe prompts the user to register and then moves the sandbox into the new account. After the user claims the sandbox, your platform receives the v2.core.claimable_sandbox.claimed event. The `owner_details` hash is populated on the claimable sandbox object. The value of `owner_details.app_install_status` depends on whether the user claimed the sandbox into an existing account or a new account. For example, if the user claims the sandbox into a new account, `app_install_status` is `pending_onboarding`. ```json { "id": "clmsbx_test_123", "object": "v2.core.claimable_sandbox", "app_channel": "public", "claimed_at": "2026-04-23T00:00:00.000Z", "created": "2026-04-22T00:00:00.000Z", "expires_at": null, "onboarding_link_details": { "expires_at": "2026-04-29T00:00:00.000Z", "refresh_url": "https://example.com/refresh", "url": "https://dashboard.stripe.com/onboard_sandbox/{{SIGNATURE}}" }, "owner_details": { "account": null, "app_install_status": "pending_onboarding" }, "prefill": { "email": "jenny.rosen@stripe.com", "country": "US" }, "sandbox_details": { "account": "acct_jenny_sandbox", "api_keys": null }, "status": "claimed" } ``` The `app_install_status` field shows the state of the owner account, which is the live account that claimed the sandbox. This field is useful for monitoring the claimable sandbox lifecycle. To learn more, see the possible enum values. In this scenario, the updated account structure looks like this after the claim: This diagram shows that the managed app sandbox of Bizbot has a connection to the claimed sandbox for Jenny Rosen (See full diagram at https://docs.stripe.com/sandboxes/claimable-sandboxes) ## User submits the account application If your user claims the sandbox into a new account, the user must onboard the Stripe account by submitting the account application before going live. After the user claims the sandbox, accessing the onboarding link again redirects the user to the account application in the Dashboard. After your user successfully submits the account application, your platform receives the v2.core.claimable_sandbox.updated event, which shows that the `app_install_status` field has updated to `pending_install`. The updated account structure looks like this after onboarding: This diagram shows that the managed app sandbox of Bizbot has a connection to the claimed sandbox for Jenny Rosen, and the live account is onboarded (See full diagram at https://docs.stripe.com/sandboxes/claimable-sandboxes) ## User installs your Stripe app into the live owner account After your user submits the account application, Stripe prompts the user to install your platform’s Stripe App in the live account. After installation, your platform receives the v2.core.claimable_sandbox.updated event, which shows that the `app_install_status` field has updated to `installed`. The `owner_details.account` field is also populated with the ID of the owner account. After installation, the sandbox `status` field changes to `live`. This indicates that the claimable sandbox object has reached the end of its lifecycle and won’t change again. At this stage, your claimable sandbox integration is complete and ready for production. ```json { "id": "clmsbx_test_123", "object": "v2.core.claimable_sandbox", "app_channel": "public", "claimed_at": "2026-04-23T00:00:00.000Z", "created": "2026-04-22T00:00:00.000Z", "expires_at": null, "onboarding_link_details": { "expires_at": "2026-04-29T00:00:00.000Z", "refresh_url": "https://example.com/refresh", "url": "https://dashboard.stripe.com/onboard_sandbox/{{SIGNATURE}}" }, "owner_details": { "account": "acct_jenny_livemode", "app_install_status": "installed" }, "prefill": { "email": "jenny.rosen@stripe.com", "country": "US" }, "sandbox_details": { "account": "acct_jenny_sandbox", "api_keys": null }, "status": "live" } ``` The following diagram shows the final account structure. This shows the relationship between the 4 different Stripe accounts. The live mode Bizbot account can access Jenny's live mode account. The sandbox app can access Jenny's sandbox. (See full diagram at https://docs.stripe.com/sandboxes/claimable-sandboxes) After installation, your platform can perform actions on both the sandbox and the live owner account on behalf of your end user. The types of actions depend on the permissions you’ve configured on your Stripe app. In the Bizbot example, after the Bizbot app is installed in the owner account, the Bizbot live account `acct_bizbot_livemode` can call APIs and listen for events from the live account `acct_jenny_livemode`. This is similar to how the Bizbot managed app sandbox account `acct_bizbot_sandbox` can access the sandbox account `acct_jenny_sandbox`. To learn more, see [How Stripe Apps work](https://docs.stripe.com/stripe-apps/how-stripe-apps-work.md). ## Use onboarding links The onboarding link for a claimable sandbox is available in the `onboarding_link_details.url` field. This stateful link redirects your user to the next action required to complete the claimable sandbox lifecycle. - If the claimable sandbox is unclaimed, the link redirects your user to the Stripe Dashboard to claim it. - If the sandbox owner account isn’t onboarded yet, the link redirects your user to the account application in the Stripe Dashboard, as long as the user has access to the claimable sandbox. - If your platform’s Stripe App isn’t installed in the owner account, the link redirects your user to a Stripe Dashboard page that explains that the app isn’t installed and includes a link to install it, as long as the user has access to the claimable sandbox. The onboarding link is active for seven days. You can find the expiration date in `onboarding_link_details.expires_at`. When the onboarding link expires, accessing the link redirects your user to the URL set in `onboarding_link_details.refresh_url`. ## Test a new app version To test a new version of your Stripe App before you publish it: 1. **Set up a test version of your app**: If you don’t already have a test version of your app, see [Test your app](https://docs.stripe.com/stripe-apps/test-app.md) for information about how to set one up. 1. **Create a claimable sandbox with `app_channel: testing`**: Use the [Claimable Sandboxes API](https://docs.stripe.com/sandboxes/claimable-sandboxes.md#api) and pass the `app_channel: testing` parameter. This creates a claimable sandbox with the test version of your app preinstalled. > Use `app_channel: testing` only for testing. This channel has restrictions. For example, you can make at most 25 live mode installs on the testing channel. After you verify that the new version works as expected, submit it to Stripe for approval and [publish it](https://docs.stripe.com/stripe-apps/publish-app.md) before you launch it to your end users. Use `app_channel: public` when you create claimable sandboxes in production. ## See also - [Create a Stripe App](https://docs.stripe.com/stripe-apps/create-app.md) - [App manifest reference](https://docs.stripe.com/stripe-apps/reference/app-manifest.md) - [Stripe MCP](https://docs.stripe.com/mcp.md)