Test mode
Test mode is a self-serve Configure account with a user already in it. One unauthenticated POST gives you a test key pair and a synthetic user whose profile is already full, so your first read comes back personalized. No signup, no dashboard, no phone of your own.
bash
curl -X POST https://api.configure.dev/v1/sandbox/provisionjson
{
"ok": true,
"claim_status": "unclaimed",
"expires_in_days": 30,
"agent": "sandbox-96d4069b",
"agent_display_name": "Sandbox Agent",
"secret_key": "sk_test_...",
"publishable_key": "pk_test_...",
"sandbox_user": {
"user_id": "1528c26b-7fd0-42f7-9dd9-2b27b8ed582a",
"external_id": "sandbox-user",
"name": "Nova Sandbrook",
"test_phone": "+12525550137",
"otp_code": "424242"
},
"livemode": false
}Save secret_key now. It is hashed at rest and never shown again. The endpoint is rate limited per IP, so script one provision per environment rather than one per test.
bash
CONFIGURE_API_KEY=sk_test_... # server only, like any secret key
CONFIGURE_PUBLISHABLE_KEY=pk_test_... # safe in the browser
CONFIGURE_AGENT=sandbox-96d4069b # the agent the sandbox created for you
CONFIGURE_TEST_PHONE=+12525550137 # sandbox_user.test_phone, minted per sandboxThose four values come out of your own provision response above, the phone number included: test_phone is minted per sandbox, so the one printed here recognizes for nobody else. With them exported, every command below runs as written.
Everything else on this site works unchanged with these values. The key prefix is the only thing that selects test mode: same host, same routes, same request shapes, same errors.
Read the synthetic user
Nova Sandbrook is an unlinked user under your sandbox developer account, so a secret key plus X-User-Id reads her:
bash
curl "https://api.configure.dev/v1/profile" \
-H "X-API-Key: $CONFIGURE_API_KEY" \
-H "X-Agent: $CONFIGURE_AGENT" \
-H "X-User-Id: sandbox-user"json
{
"linked": true,
"identity": {
"name": "Nova Sandbrook",
"email": "nova.sandbrook@example.com",
"occupation": "Freelance industrial designer",
"location": "Portland, Oregon",
"sandbox": true
},
"preferences": [
"Communication: direct and concise; bullet points over prose",
"Schedule: deep work before noon; no meetings on Thursdays (boatyard day)",
"Diet: vegetarian; shellfish allergy (severe); oat-milk flat whites"
],
"livemode": false
}The fixture is a real profile, written through the same storage the live plane uses: identity, preferences, a summary, typed memories, and connected Gmail and Calendar accounts with canned mail and events. That is the point of the sandbox. An empty account cannot show you what a personalized first message reads like.
livemode
Every JSON object a test key produces carries livemode: false, including error bodies. Live responses are untouched, so the field is how a client tells the two planes apart without inspecting keys:
json
{ "error": { "code": "tool_not_connected" }, "request_id": "req_...", "livemode": false }Test and live data cannot see each other. A test key resolving a live user, or a live key resolving a test user, does not resolve at all: the user is not found rather than forbidden.
Sign in as the synthetic user
The test phone is in the fictional +1 NXX 555-01XX range that can never receive a message, and its OTP is fixed at 424242. Under a test key that code verifies with no provider round trip. Under a live key these numbers get no special treatment at all: the code goes to the SMS provider and fails like any wrong code.
Use it to drive your own sign-in UI end to end. The hosted components and the OTP endpoints both accept it:
bash
curl -X POST https://api.configure.dev/v1/auth/otp/start \
-H "X-API-Key: $CONFIGURE_API_KEY" -H "X-Agent: $CONFIGURE_AGENT" \
-H 'Content-Type: application/json' \
-d "{\"phone\":\"$CONFIGURE_TEST_PHONE\"}"
curl -X POST https://api.configure.dev/v1/auth/otp/verify \
-H "X-API-Key: $CONFIGURE_API_KEY" -H "X-Agent: $CONFIGURE_AGENT" \
-H 'Content-Type: application/json' \
-d "{\"phone\":\"$CONFIGURE_TEST_PHONE\",\"code\":\"424242\",\"agent\":\"$CONFIGURE_AGENT\"}"That returns a user token, which is what a browser sign-in produces. Server-side calls want an agent token instead, and the synthetic user has already approved the sandbox agent, so phone recognition hands you one in a single call:
bash
curl -X POST https://api.configure.dev/v1/auth/sign-in/recognize-phone \
-H "X-API-Key: $CONFIGURE_API_KEY" -H "X-Agent: $CONFIGURE_AGENT" \
-H 'Content-Type: application/json' \
-d "{\"candidates\":[\"$CONFIGURE_TEST_PHONE\"]}"json
{
"matched": true, "approved": true, "linked": true,
"userId": "1528c26b-7fd0-42f7-9dd9-2b27b8ed582a",
"agent": "sandbox-96d4069b",
"token": "eyJhbGciOiJIUzI1...",
"displayName": "Nova Sandbrook",
"livemode": false
}You need that token for connector calls, so keep it: pipe the call above through | jq -r .token and assign it, TOKEN=$(curl -sS ... | jq -r .token). X-User-Id developer scope covers profile read, search, and remember; connector query endpoints require an agent-scoped token, in test mode exactly as in live.
bash
curl -X POST https://api.configure.dev/v1/connectors/gmail/messages/search \
-H "X-API-Key: $CONFIGURE_API_KEY" -H "X-Agent: $CONFIGURE_AGENT" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"query":"harbor","max_results":2}'The mail comes back from the fixture: a design review from her anchor client, a shipping notice from a chandlery. No provider is contacted.
Break it on purpose, then put it back
Two endpoints, both authenticated with your sk_test_ key. They exist so you can write the unhappy path before a real user ever hits it.
bash
# Make Gmail behave like a connection whose token died.
curl -X POST https://api.configure.dev/v1/sandbox/simulate \
-H "X-API-Key: $CONFIGURE_API_KEY" -H "X-Agent: $CONFIGURE_AGENT" \
-H 'Content-Type: application/json' \
-d '{"scenario":"gmail_token_expired"}'Gmail calls on this sandbox now fail the way a dead Composio connected account fails: HTTP 400, tool_not_connected, retryable: false. Handling that failure is the subject of connector repair. Calendar and profile reads are unaffected.
bash
# Restore the synthetic user to pristine: test-plane writes deleted, fixture reseeded.
curl -X POST https://api.configure.dev/v1/sandbox/reset \
-H "X-API-Key: $CONFIGURE_API_KEY" -H "X-Agent: $CONFIGURE_AGENT"Reset also clears the simulated scenario, so a test suite can reset between cases and start from the same profile every time.
gmail_token_expired is the only scenario today.
Lifetime and going live
An unclaimed sandbox expires 30 days after it is provisioned, and everything it created is removed with it. Provision another whenever you need one.
Nothing carries over to a live account, by design: test data never appears on the live plane. When you are ready for real users, get live credentials the ordinary way (Get your credentials) and change the two keys in your environment. No code changes, because nothing on the request side differs.
Do not point a sandbox at a real user. The test plane is for the synthetic user, and the fictional phone range means no one can be messaged by accident.