On this page

Multi-tenant SaaS

~12 min Python TypeScript

Goal: Embed MIOSA into a multi-tenant product. Every sandbox is tagged with your own workspace and user IDs. Usage rolls up per tenant for billing. End-users interact with their sandboxes directly from the browser without ever seeing your API key.

What you’ll use: Sandboxes, External Attribution, Browser Tokens, Usage API

What you’ll build

An embedded sandbox experience inside your SaaS:

  1. Your backend creates sandboxes tagged to the right customer.
  2. Each tenant’s usage is queryable for chargeback.
  3. Your customer’s browser gets a short-lived token to embed a live preview — no msk_* key anywhere client-side.

Prerequisites

  • A MIOSA workspace API key (msk_live_*) — see API Keys
  • Node 22+ or Python 3.11+

Step 1 — Install and configure

Step 2 — Tag every sandbox with your IDs

Pass external_workspace_id, external_user_id, and external_project_id on every sandboxes.create call. MIOSA stores these on the resource row and propagates them to every usage record, audit event, and derived resource (previews, deployments) automatically.

Step 3 — List sandboxes per tenant

Filter the sandbox list by your own IDs to show a customer only their resources, or to enumerate all sandboxes for an account before billing.

Step 4 — Query usage per tenant

Pull a usage report grouped by external_workspace_id at the end of each billing period. Use this to generate invoices or display a cost dashboard inside your product.

Step 5 — Issue browser tokens for direct access

Your customer’s browser needs to embed a live preview. You cannot put msk_* in the frontend. Instead, your backend mints a short-lived share token and returns it to the client.

Backend — mint the token:

Frontend — embed the preview:

<!-- Fetch the token from your backend, then embed the iframe -->
<script>
  async function embedPreview(sandboxId) {
    const resp = await fetch(`/api/sandboxes/${sandboxId}/preview-token`);
    const { shareUrl, expiresAt } = await resp.json();

    const iframe = document.getElementById('preview-frame');
    iframe.src = shareUrl;

    // Re-mint before expiry so the session stays alive
    const expiryMs = new Date(expiresAt).getTime() - Date.now() - 60_000;
    setTimeout(() => embedPreview(sandboxId), expiryMs);
  }

  embedPreview('sbx_...');
</script>

<iframe
  id="preview-frame"
  sandbox="allow-same-origin allow-scripts allow-forms"
  style="width: 100%; height: 600px; border: 0;"
></iframe>

Step 6 — Full integration wiring

Here is the complete server-side flow for a new-user onboarding request:

What you learned

  • Three external ID fields (external_workspace_id, external_user_id, external_project_id) let you group every MIOSA resource by your own identifiers without any server-side MIOSA configuration.
  • Usage reports group by the same IDs — direct input to your chargeback logic.
  • Share tokens are resource-scoped, expirable, and the only credentials that should reach a browser. The msk_* key stays on the backend at all times.
  • Attribution is inherited: a deployment published from a tagged sandbox carries the same external IDs automatically.

Next

Was this helpful?