Run Spaces as your own tenant
Spaces — the multiplayer-AI room — is the reference app on Witbitz. This page runs it as you: your own origin, your own key vault, your own keys. You write no code; Witbitz builds and hosts it, and you can prove what it deployed.
One paste
Needs curl and python3. Nothing to clone, no Cloudflare account.
# 1) Register (free). The secret is shown ONCE and cannot be reissued — this saves it.
resp=$(curl -sX POST https://api.witbitz.chat/v1/tenants/demo \
-H 'content-type: application/json' -d '{"name":"My Space"}')
export TENANT_KEY=$(echo "$resp" | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["keys"]["secret"])')
export TENANT_ID=$(echo "$resp" | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["tenant"]["tenant_id"])')
umask 077
{ echo "# $(date -u +%Y-%m-%dT%H:%M:%SZ)"; echo "TENANT_ID=$TENANT_ID"; echo "TENANT_KEY=$TENANT_KEY"; } >> ~/.witbitz-tenants
echo "saved → ~/.witbitz-tenants (the only copy — lose it and this tenant is unreachable)"
# 2) Ask for your app. Names are first-come, first-served; set SLUG=yourname for a specific address.
SLUG="${SLUG:-myspace-$(od -An -N2 -tu2 /dev/urandom | tr -d ' ')}"
r=$(curl -sX POST https://api.witbitz.chat/v1/tenant/app \
-H "authorization: Bearer $TENANT_KEY" -H 'content-type: application/json' \
-d "{\"slug\":\"$SLUG\"}"); echo "$r"
# 3) Watch it — two builds and two deploys, about 90 seconds.
while s=$(curl -s https://api.witbitz.chat/v1/tenant/app -H "authorization: Bearer $TENANT_KEY"); echo "$s"; ! echo "$s" | grep -qE '"status":"(live|failed)"|"error"'; do sleep 20; doneIt ends with your address:
{"status":"live","slug":"myspace-41287","url":"https://myspace-41287.witbitz.chat", …}What you got
- A vault at
<slug>.witbitz.chat— the small key-holder that runs sign-in and confines your keys. It is the address you give people and the one they install. The app it frames sits at<slug>-app.witbitz.chat. - The app, which is Spaces. You write nothing. Witbitz builds the reference app from a pinned commit and deploys it to your origins. Your copy is pinned to your deploy — it does not change when the reference app updates.
- Your own keys. A
K_econobody else holds, so your rooms are cryptographically isolated from every other tenant's; your own app key; your own OTP namespace. Rooms are stamped to you and split-key by default. - Your own look. An accent colour and name derived from your slug — the welcome page, the icon and the installed app carry them, so yours is not a second copy of ours on someone's home screen.
- Sign-in that needs no setup. Google and email codes run through the central Witbitz auth service, minted as your origin. Nothing to register with Google.
While you wait
A workflow runs it one named step at a time: create the projects and the domain, mint your keys, build and deploy the vault, configure it and redeploy, the same for the app, then admit your origins, register your issuers and grant your permissions. If any step fails the ones before it are undone — projects, namespaces, keys and secrets deleted rather than left as debris — and the poll tells you which step failed.
status |
|
|---|---|
queued · provisioning |
still running — keep polling |
live |
deployed, configured and admitted; url is your address |
failed |
error names the step; everything it created has been undone |
When it refuses: refused — the slug is malformed or reserved. conflict — that name is another tenant's.
too_many_requests — ten apps per address per day; registering a fresh tenant does not reset it. A refusal queues
nothing, so there is no job to poll.
One app per tenant. Re-asking with the same slug re-provisions it, keeping your K_eco so existing rooms still open.
Taking it down
Three levels, because they are three decisions. Each needs the key for that tenant.
# 1. The app: projects, domain, admission, its key. KEEPS K_eco, so your rooms survive.
curl -sX DELETE https://api.witbitz.chat/v1/tenant/app -H "authorization: Bearer $TENANT_KEY"; echo
while s=$(curl -s https://api.witbitz.chat/v1/tenant/app -H "authorization: Bearer $TENANT_KEY"); echo "$s"; ! echo "$s" | grep -qE '"status":"(deleted|live)"|"error"'; do sleep 10; done
# 2. The rooms and everything in them. GET first — it deletes nothing and returns the confirmation value.
curl -s https://api.witbitz.chat/v1/tenant/rooms -H "authorization: Bearer $TENANT_KEY"; echo
curl -sX DELETE https://api.witbitz.chat/v1/tenant/rooms -H "authorization: Bearer $TENANT_KEY" \
-H 'content-type: application/json' -d "{\"confirm\":\"$TENANT_ID\",\"slug\":\"$SLUG\"}"; echo
# 3. The account: every key, every row.
curl -sX DELETE https://api.witbitz.chat/v1/tenant -H "authorization: Bearer $TENANT_KEY" \
-H 'content-type: application/json' -d "{\"confirm\":\"$TENANT_ID\"}"; echoTaking the app down keeps K_eco, the key your rooms' halves are sealed under — deleting it would not delete the
rooms, it would make them permanently unopenable. Put the same slug back and they open again. Step 2 is what removes
them, and it takes K_eco last. Step 3 refuses while an app or rooms remain, and tells you what is left.
Steps 2 and 3 are irreversible, so each must name the tenant it is destroying. Ask without the confirmation and the reply gives you the value.
In a new shell: set -a; . ~/.witbitz-tenants; set +a.
Proving what it deployed
Your app ships an asset manifest — every file hashed, stamped with the commit it was built from:
curl -s https://<slug>-app.witbitz.chat/assets-manifest.json | head -3
# → {"v":1,"gitCommit":"…","algo":"sha256", …}That commit is the platform build your app was made from, and that build is fully verifiable: rebuild the published source and get the hash AWS runs (Verify it, Tests 6–7). The client is served unminified, so you can also just read it.
Your origin also serves its own signed certificate, bound to that origin, committing to the exact bytes above:
curl -s https://<slug>.witbitz.chat/cert.json | python3 -c 'import sys,json;print(json.load(sys.stdin)["signed"])'
# → {"service":"witbitz-vault","env":"tenant","origin":"https://<slug>.witbitz.chat","frontendSha256":"…", …}So the verified-client extension reports your origin as verified, and builds the policy it enforces from that signed manifest rather than from your page.
Two limits, stated plainly rather than left to be discovered:
- It is signed by the tenant key, not the platform key. That key lives in the provisioning pipeline, and the
verifier accepts it only on tenant origins — so it can attest what it deployed for you and can never speak for
spaces.witbitz.chat. The separation is the point; it also means your certificate is only as trustworthy as that pipeline. - It commits to the frontend, not to a backend. Your tenant does not run its own render, so the certificate claims the bytes it served and nothing more. The reproducible-source check (Test 7) still runs against the first-party app — the same code at the commit your manifest names.
Everything else on the Verify it page — the admission gate, the egress lock, the sealed store — is checkable against your own Space today.
Keeping it
A demo tenant is real and works immediately, but auto-purges at its expires_at. To make it permanent — same id and
keys — upgrade with an author coupon, or sign up non-expiring from the start with POST /v1/tenants/signup:
curl -sX POST https://api.witbitz.chat/v1/tenant/upgrade \
-H "authorization: Bearer $TENANT_KEY" -H "X-Author-Coupon: <code>"No coupon? Email hello@witbitz.chat.
Not locked in. Witbitz-hosted is the easy default, not the only one. The same app is portable: point its one backend switch at your own boundary and run the entire stack yourself — same code, same verifiable-privacy properties. To embed a Space in a page you already have, see embed.
Next
- Verify it — prove the deployed bytes are the published, readable code.
- Deployment options · Embed · HTTP API · SDK
Machine-readable source: vault-spaces.md · Generated 2026-10-27T07:05:42Z · build f301388c · every doc in one fetch: llms-full.txt (HTML)