White-label SaaS - end-to-end walkthrough
This walkthrough builds OpenDesigns, a design-tool SaaS where each customer gets an isolated workspace. OpenDesigns’s end users never see the MIOSA brand: the domain is opendesigns.ai, the product name is “OpenDesigns Workspaces”, and the failure pages show the OpenDesigns logo.
Everything here maps directly to working code in examples/whitelabel-saas.
Prerequisites
- A MIOSA account with a workspace-scoped API key (
msk_w_...) - DNS access to your domain (for preview domain setup)
- Python 3.9+ or Node 18+ depending on which code tabs you follow
One-time setup
Run this once after account creation. It is safe to re-run - each step checks the current state and skips if already configured.
Set branding
Register a preview domain
Add two wildcard CNAME records at your DNS provider before continuing:
| Record type | Name | Value |
|---|---|---|
CNAME | * | proxy.miosa.ai |
CNAME | *.sandbox | proxy.miosa.ai |
Verify after DNS propagates (typically 1-5 minutes):
Register a webhook
Per-user provisioning
Create one sandbox per customer project. Pass your own IDs so you can look up, filter, and bill these resources later.
Field reference:
| Field | Purpose | Example |
|---|---|---|
external_user_id | Your customer’s stable identifier. Used for usage rollup, quota checks, and filtering. | "user_42" |
external_project_id | Your project’s identifier within a customer. | "proj_opendesigns_1" |
name | URL-safe slug that appears in preview URLs until a custom domain is set. | "brand-refresh-2026" |
metadata | Arbitrary key-value pairs returned in webhook payloads and API responses. | {"source": "opendesigns"} |
Pretty URLs
By default, sandbox previews use *.sandbox.opendesigns.ai after you register your preview domain. To give each sandbox a human-readable subdomain, update the slug after creation:
Slugs must be unique within your workspace. If a slug is already taken, MIOSA returns a 409 conflict.
Embed a preview in an iframe
Never expose your API key to the browser. Your backend mints a short-lived preview token; the browser sets it as the <iframe src>.
In the browser:
<iframe
id="workspace-frame"
src="https://3000-brand-refresh-2026.sandbox.opendesigns.ai?token=mp_..."
allow="clipboard-read; clipboard-write"
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
style="width: 100%; height: 700px; border: none;"
title="OpenDesigns Workspace"
></iframe> See Preview Tokens for token refresh, permission scoping, and early revocation.
Get notified: webhook subscription
The POST /webhooks/miosa handler verifies the HMAC-SHA256 signature and dispatches events:
For the complete signature verification spec and retry policy, see Webhooks.
Customize after create
Update sandbox settings at any time without recreating the VM:
Bill by user
Query compute usage keyed to your external_user_id. Use this for per-seat billing, usage dashboards, or chargeback reports.
Per-user quotas
Prevent a single customer from consuming your entire compute budget. Set quotas at the workspace or project level, or enforce them in your own API layer:
Branded failure pages
502 and 404 errors in previews will show your branding once product_name and logo_url are set (see one-time setup). No additional configuration is needed. The preview proxy reads your tenant branding automatically.
Public sharing
Create a public share link for a sandbox preview - useful for design reviews or peer feedback:
Revoke a share before it expires:
End-user file tree, terminal, and run buttons
Give your users a native feel with file browsing, terminal, and run-button components backed by the MIOSA SDK. All three require a browser token with the appropriate scopes (see Preview Tokens - permission scoping).
File tree
Terminal
Run button
Teardown on cancellation
Destroy all sandboxes when a customer cancels their account:
End-to-end checklist
- Set branding:
product_name,logo_url,support_email - Register preview domain and add DNS CNAMEs
- Verify DNS propagation
- Register webhook and store the secret in your environment
- Create sandboxes with
external_user_id,external_project_id, andmetadata - Mint preview tokens server-side only - never expose
msk_*to the browser - Verify HMAC-SHA256 on every webhook delivery
- Reject stale webhook timestamps (>5 min)
- Deduplicate webhook events by
event.id - Query usage by
external_user_idfor billing - Enforce per-user sandbox quotas before creating
- Destroy sandboxes on cancellation
See also
Token format, TTL strategy, iframe attachment, refresh, and permission scoping.
Full event taxonomy, HMAC verification in 3 languages, idempotency, retries.
Domains, branding, workspace and project scoping, domain precedence.
Ownership fields, external IDs, usage reconciliation.