Apps
Public mini apps stored inside a workspace and published at /apps/[handle]
Apps are public mini apps that belong to one workspace.
Each app stores:
namehandle- optional
description codememberRole- optional
memberPermissions - optional
publicRole - optional
publicPermissions runtimeKeyTtlMs
Public URL
Every app is published at:
/apps/[handle]The public page renders the saved JSX inside a sandboxed iframe.
Code contract
For now, code must be a single JSX module that exports a default React component.
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
return (
<main style={{ minHeight: "100vh", padding: 24 }}>
<h1>Counter</h1>
<button onClick={() => setCount((value) => value + 1)}>
Count: {count}
</button>
</main>
);
}The renderer loads React from esm.sh, transpiles the JSX in-browser, and mounts the default export into the iframe root.
API endpoints
Apps are documented in the generated API reference:
GET /api/v1/experimental/apps: list apps for the current workspaceGET /api/v1/experimental/apps/:handle: get one public app by handlePOST /api/v1/experimental/apps/:handle/runtime-token: issue or refresh an embedded-app runtime keyPOST /api/v1/experimental/apps: create an app in the current workspacePATCH /api/v1/experimental/apps/:handle: update an app in the current workspaceDELETE /api/v1/experimental/apps/:handle: delete an app from the current workspace
Use the full request and response schemas here:
Runtime auth model
Public apps do not receive long-lived secrets in HTML or query params.
Instead, the host page waits for the iframe runtime to post andibase:ready, then it calls:
POST /api/v1/experimental/apps/:handle/runtime-tokenThe response includes:
apiKeybaseApiUrlworkspaceHandlepermissionsaccessModeexpiresAtrefreshAfterappSessionId
The iframe keeps that bootstrap in memory only and exposes it through window.andibase.
Member vs public access
- Signed-in workspace members receive the app's member grant.
- Anonymous viewers receive the app's public grant.
- Signed-in non-members also receive the public grant.
- New apps default the member grant to
admin. - New apps default the public grant to no permissions.
Runtime permissions are recomputed from the app row on every bootstrap and refresh.
Refresh behavior
- Runtime keys default to a 5 minute TTL.
refreshAfteris one minute before expiry for normal TTLs.- When the TTL is shorter than 2 minutes, refresh shifts to 80% of the lifetime.
- The iframe asks the parent page for a replacement key before expiry.
- The old key remains valid until its natural expiration, so in-flight requests can finish while new requests switch to the replacement key.
- If refresh fails twice and the old key expires, the iframe enters an auth-expired state until the parent completes another bootstrap handshake.
Auth model
GET /api/v1/experimental/apps/:handleis public and does not return runtime grant fields.- Workspace management endpoints use the resolved workspace.
- Session requests should send
x-workspace-handlewhen needed. - Manual API keys still need
apps.readorapps.write.