Skip to content
Go To Dashboard

App Links

An App Link is a durable Sapiom-hosted URL for a small web app — a dashboard, a demo, an internal tool, a workflow UI:

https://apps.sapiom.ai/{your-org}/{your-app}

The link is the durable thing, not the sandbox behind it. You publish a bundle once; the URL keeps working. When someone opens it, Sapiom checks who they are, wakes the app from the stored bundle if nothing is running, and hands them over to it. Sandboxes stay short-lived and disposable — the link outlives all of them.

That is the difference from a sandbox preview URL, which lives and dies with its sandbox: when the TTL expires, the preview link stops resolving. See Compute for sandboxes themselves.

Nothing runs between visits. That keeps an App Link cheap — you pay for the seconds an app is actually awake, not for idle hosting — and it is the main thing to understand before you share one:

  1. A visit arrives. Sapiom verifies the visitor may open this app.

  2. If the app is already awake, the visit is handed straight to it. This is fast.

  3. If nothing is running, the visitor sees a “Starting …” page while Sapiom creates a sandbox and deploys your bundle. Expect tens of seconds. The page redirects itself when the app is ready.

The first visit after a publish is always a cold start. So is the first visit after the app has been idle long enough for its sandbox to expire.

A publish needs three things: the app’s files as UTF-8 text, the command that starts it, and the port it listens on. start runs inside a fresh sandbox on every wake, so the bundle must be self-contained.

Which surface you reach for depends on where the app already lives. From a project on disk, the local tool reads all three out of sapiom.json for you; the hosted MCP and REST take an explicit file map.

In Agent Studio — or any coding agent on the local sapiom-dev MCP — call sapiom_dev_app_publish. It is the durable sibling of sapiom_dev_sandbox_preview: same project, same sapiom.json type: "sandbox" resource, different destination.

{
"slug": "quarterly-dashboard",
"name": "Quarterly dashboard"
}

There is no file map. The tool reads the source directory, start, port, and the optional build and env out of the sandbox resource you already configured with sapiom_dev_sandbox_configure, uploads that source as a stored bundle, and activates it. node_modules, .git, dotfiles, symlinks, and sapiom.json itself are never uploaded — install dependencies at wake with build.

Add resource when the project defines more than one sandbox resource, dir when the project is not your working directory, and visibility with confirmPublic and dailySpendCapUsd to publish a public app. It returns { url, appLinkId, bundleSha256, manifest }.

The 10 MiB bundle cap and the text-only rule are both enforced locally, before any upload, so a bad bundle costs no round trip and never leaves a half-published link behind.

Publishing to a slug you already own replaces the app at the same URL. That is how you ship an update: the link you shared last week keeps working and starts serving the new bundle on its next wake. Identity is the (organization, slug) pair, so a link is only ever replaced deliberately — nothing republishes as a side effect of an unrelated deploy.

Only logged-in members of the organization that owns the app can open it. A visitor who is not signed in is sent to log in first, and one who is signed in but not a member does not get through.

  • Text only. UTF-8 files — HTML, CSS, JS, JSON, TypeScript. Images, fonts, and archives are rejected at publish rather than silently corrupted. Inline small assets as SVG or data URLs, or fetch them from a CDN at runtime.
  • Self-contained. start has to work in a fresh sandbox. Use the optional build command (for example npm install) for dependencies — it runs on every wake, so keep it quick.
  • Environment variables are set on the app itself (the env map on sapiom_app_publish, or on POST /v1/app-links), injected into the process at wake, and stored encrypted — only the key names are ever read back. Setting env again replaces the whole map.
  • No durable state inside the app. Every wake is a fresh sandbox from the bundle, so anything written to its filesystem or held in memory is gone. Apps that need to remember something should use a database.

An App Link can also receive webhooks, which is what makes a Slack bot or a callback receiver practical on a sandbox that is usually asleep. Enable webhooksEnabled on the app, and everything under the link’s /hook/ path is forwarded to it:

https://apps.sapiom.ai/{your-org}/{your-app}/hook/slack/events
  • The routing prefix is stripped — the app above sees /slack/events.
  • Bodies are forwarded byte-exact, so signature verification inside your app works (Slack, Stripe, and GitHub all sign the raw body). Body cap: 1 MB.
  • A request that arrives while the app is asleep is held while it wakes, up to 60 seconds, then forwarded.
  • Slack URL-verification challenges are answered without waking anything, so registering the endpoint always succeeds.
  • Not always-on hosting. Cold starts of tens of seconds are the design, not a bug.
  • Not a place for stateful apps. Each wake redeploys from the bundle; use a database for anything that must persist.
  • Not for binary assets. Bundles are UTF-8 text.
  • Not custom domains. Apps are served under apps.sapiom.ai.