Sandbox & claim API
A sandbox is a real ShowroomPro ring builder that nobody owns yet. An agent or developer creates one with a single unauthenticated request, installs its snippet, and hands the jeweler a claim link. Claiming turns it into a normal account without changing the token, so nothing on the site has to change.
Base URL: https://www.showroompro.ai. CORS is open, so the API can also be called from a browser. The full schema is in the OpenAPI spec.
#Create a sandbox
POST /api/v1/sandboxes
curl -s -X POST https://www.showroompro.ai/api/v1/sandboxes \
-H "Content-Type: application/json" \
-d '{"businessName":"Atelier Rose Jewelers","websiteUrl":"atelierrose.example","platform":"wix","source":"cursor"}'const res = await fetch("https://www.showroompro.ai/api/v1/sandboxes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ businessName: "Atelier Rose Jewelers", platform: "wix", source: "cursor" }),
});
const sandbox = await res.json();#Request body
All fields are optional. An empty body works.
| Field | Type | Notes |
|---|---|---|
businessName | string | Up to 120 characters (longer values are cut). Pre-fills the claim form. |
websiteUrl | string | An http(s) URL or a bare domain like example.com. Anything else returns 400. |
platform | string | shopify, wix, squarespace, wordpress, woocommerce, webflow, bigcommerce, custom or other. Unknown values are stored as other. |
source | string | Your agent or tool name, for example claude-code, cursor, codex, copilot. agent is accepted as an alias. |
#Response: 201 Created
| Field | Description |
|---|---|
object | Always "sandbox". |
apiVersion | API version date, for example "2026-10-13". |
id | Sandbox ID. |
status | "unclaimed". |
quizToken | Public token used by every snippet. Safe to put in page code. |
quizUrl | Hosted quiz page. Works as a plain link (for example from Instagram or email). |
claimUrl | Private. Give it only to the jeweler. Don't commit it, put it in page code or post it publicly. |
expiresAt | ISO timestamp when the unclaimed sandbox stops working. |
renders | { limit, used, remaining } AI renders for the unclaimed sandbox. |
snippets | inline, floating, popup and iframe HTML. See the widget reference. |
business | Echo of name, websiteUrl and platform. |
source | Normalized source name. |
notes | Plain-language notes worth relaying to the user. |
#Limits for unclaimed sandboxes
| Limit | Value |
|---|---|
| AI renders per sandbox | 3 in total |
| Lifetime | 14 days, then the quiz stops |
| Removal | 30 days after expiry; until then it can still be claimed |
| Create rate | 5 per IP per hour, 20 per IP per day |
While unclaimed, a sandbox:
- captures every lead. After the render limit, shoppers can still finish the quiz and their designs wait for the jeweler;
- sends no emails to shoppers or to the jeweler, sends no alerts and fires no webhooks;
- uses neutral branding and shows a small "Powered by ShowroomPro — unclaimed" note.
GET /api/v1/sandboxes returns the current limits and the request contract as JSON, so you can check them at runtime.
#Check status
GET /api/v1/sandboxes/status/{quizToken}
curl -s https://www.showroompro.ai/api/v1/sandboxes/status/YOUR_TOKEN{
"object": "sandbox_status",
"apiVersion": "2026-10-13",
"id": "…",
"status": "unclaimed",
"claimed": false,
"expiresAt": "2026-10-30T12:00:00.000Z",
"renders": { "limit": 3, "used": 0, "remaining": 3 },
"installDetected": true
}status is unclaimed, claimed, expired or purged. installDetected becomes true once embed.js has loaded on a real (non-localhost) domain. No auth is needed because the quiz token is already public on the site.
#Errors
Errors share one shape:
{
"object": "error",
"apiVersion": "2026-10-13",
"error": { "code": "invalid_request", "message": "websiteUrl must be an http(s) URL or domain such as example.com", "field": "websiteUrl" }
}| Status | code | What to do |
|---|---|---|
| 400 | invalid_request | Fix the field named in field. |
| 404 | not_found | Status check only: no sandbox uses this token. |
| 429 | rate_limited | Too many sandboxes from this network. Wait retryAfterSeconds (also in the Retry-After header), or send the user to signupUrl. |
| 429 | capacity_exhausted | Sandbox creation is paused. Same handling as rate_limited. |
| 500 | internal_error | Retry once. |
Don't create a new sandbox on every run. Create one per website and reuse its token.
#Claiming
The jeweler opens claimUrl and either:
- creates an account. This starts a 7-day free trial. The sandbox's token, quiz and leads become theirs; or
- signs in to an existing ShowroomPro account and merges the ring builder into it. The pasted snippet keeps working, and leads captured so far move into that account.
After claiming, the jeweler's normal plan limits, branding, emails and webhooks apply. The claim link only works once.
Claiming doesn't need any API call from the agent. Poll the status endpoint if you want to tell the user when it happened.