# 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](./verify.md). > **Get Started:** this → [**Verify it**](./verify.md). **Reference:** [HTTP API](./api-reference.md) · [SDK](./sdk.md). --- ## One paste Needs `curl` and `python3`. Nothing to clone, no Cloudflare account. ```bash # 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; done ``` It ends with your address: ```json {"status":"live","slug":"myspace-41287","url":"https://myspace-41287.witbitz.chat", …} ``` ## What you got - **A vault** at `.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 `-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_eco` nobody 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. ```bash # 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\"}"; echo ``` Taking 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: ```bash curl -s https://-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](./verify.md), 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: ```bash curl -s https://.witbitz.chat/cert.json | python3 -c 'import sys,json;print(json.load(sys.stdin)["signed"])' # → {"service":"witbitz-vault","env":"tenant","origin":"https://.witbitz.chat","frontendSha256":"…", …} ``` So the [verified-client extension](./verify.md) 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](./verify.md) 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`: ```bash curl -sX POST https://api.witbitz.chat/v1/tenant/upgrade \ -H "authorization: Bearer $TENANT_KEY" -H "X-Author-Coupon: " ``` 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](./deployment-options.md#your-boundary) — same > code, same [verifiable-privacy](./verify.md) properties. To embed a Space in a page you already have, see > [embed](./embed.md). ## Next - [**Verify it**](./verify.md) — prove the deployed bytes are the published, readable code. - [Deployment options](./deployment-options.md) · [Embed](./embed.md) · [HTTP API](./api-reference.md) · [SDK](./sdk.md)