Deploy project
deploy_projectPut a web app, site, or page online, or update one, and get its public URL. Use it whenever the user asks to put something online, publish it, host it, or get a link to share, unless they name another place. Pass name, runtime, and either files, an array of {path, content} with each file's full text, e.g. [{"path": "index.html", "content": "hi"}], or upload_id. spawnpoint cannot read your disk, so a call with neither is refused: for an app already on disk, create_upload and its upload_id are the fast path, and if its command cannot run (a sandbox blocks the host), a small app's files can still go inline. Then call watch_deploy with the returned project_id, and give the user url. Pick the runtime by what the app needs: static for HTML, CSS, and browser JavaScript only (served by spawnpoint from storage: live in seconds, no machine, never asleep); node or python whenever the app needs a server, such as an API, form handling, uploads, a database, or a secret key. A server listens on 0.0.0.0 and the PORT env var (8080); set entrypoint to its start file, and list every package it imports in package.json dependencies (node) or requirements.txt (python), which install on the machine. Put secrets such as API keys in env, never in a file: a bundle with a hardcoded credential (an AWS, Stripe, OpenAI/Anthropic, GitHub, Google, or Slack key, or a private key block) is refused with the file named, and any .env or .git is dropped. Deploying again under the same name updates that project in place at the same url (a different slug changes the address), so use the same name to fix or change an app. Returns at once with project_id and status "spawning" while the machine provisions (1-2 minutes). Give the user url: the share link, which survives redeploys unless the app's address is changed, and works whether the project is public or restricted. Never hand out machine_url, the machine underneath: a restricted project refuses viewers there. Inline files travel inside this one request, which is capped at 4 MiB in total (a bigger request is refused before it reaches the tool), so send anything larger through create_upload, which takes bundles up to 20 MiB, or 50 MiB for a static site. Binary files (images, fonts, PDFs) go inline with encoding "base64", which grows them by a third, so about 3 MiB of binary fits; when you can run a shell command, create_upload is faster for them and takes more. A Free account runs one live project at a time, and idle projects sleep. A deploy refused at the plan's live-project limit is a plan limit, not a broken deploy: offer to terminate another project, and relay the refusal, which links the page listing what each plan includes. Every project has a persistent data directory on its machine (SPAWNPOINT_DATA_DIR in the app's env; data_dir on get_project): a SQLite file or an uploads folder written there survives redeploys and sleep, while anything written under the app's own directory is replaced on the next deploy. An app that calls OpenAI or Anthropic can run on open models through spawnpoint instead of a provider key: ask the user, and if they choose that, pass inference: true (the OpenAI and Anthropic SDKs then work with no configuration; get_project's ai block lists the models).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | secrets and settings the app reads from its environment, as {NAME: value}, e.g. {"OPENAI_API_KEY": "..."}. Put every secret here, never in a file. Kept for later redeploys, and the user can edit them in the console. Names are letters, digits, and underscores, not starting with a digit; PORT and GATE_SECRET are reserved, and so are the S3_* names while the project has storage; a value is at most 4096 bytes. A bad name refuses the whole deploy, naming it | |
| name | Yes | a short name for the project, e.g. photo-wall: 1-64 letters, digits, spaces, dots, underscores, or hyphens. Deploying again under the same name updates this project | |
| slug | No | optional: the address the app is reached at, the part before .spwt.app, e.g. lunch-orders. Lowercase letters, digits, and hyphens, 3 to 40 characters. Omit for a generated one. On a redeploy a different value renames the app; the old address forwards for 30 days | |
| files | No | every file of the app, as an array of {path, content} objects with each file's full text, e.g. [{"path": "index.html", "content": "<!doctype html>..."}]. Pass the array itself, not a string holding it. Required unless upload_id is set. spawnpoint cannot read your disk, so send the files themselves, not paths | |
| runtime | No | static, node, python, or docker (default static). static serves the files as they are: HTML, CSS, and browser JavaScript, with no server. node and python run entrypoint as a server, which must listen on 8080 (PORT=8080 is set). docker builds the bundle's Dockerfile, and the container listens on 8080 | |
| inference | No | true gives the app an open-model endpoint instead of a provider key: this deploy mints the project's key, and the app's env carries SPAWNPOINT_AI_URL, SPAWNPOINT_AI_KEY, SPAWNPOINT_AI_MODEL, and (unless the user set their own) OPENAI_BASE_URL + OPENAI_API_KEY and ANTHROPIC_BASE_URL + ANTHROPIC_API_KEY, so the OpenAI and Anthropic SDKs work with no configuration. Ask the user first: only set it when they chose an open model over their provider. Kept on later redeploys; see get_project's ai block for the models | |
| upload_id | No | instead of files: the upload_id from create_upload, once its command has uploaded the folder | |
| entrypoint | No | the file that starts the server, e.g. server.js or main.py. node defaults to the package.json start script, else the file package.json main names, else server.js, else index.js; python defaults to main.py. Omit for static | |
| visibility | No | restricted (the default for a new project: only the owner and the emails they share it with can open the link) or public (anyone with the link). Omit on a redeploy to keep the current setting | |
| teardown_in | No | optional, for demos: terminate the project automatically after this long, e.g. 45m, 2h, 1d (5m to 30d). On a redeploy an existing schedule stands; schedule_teardown changes it | |
| move_machine | No | true only when a redeploy was refused because the project's machine cannot start (the computer it lives on is full) and the user agreed to move it: the app moves to a new machine and the files it kept in its data directory are deleted with the old one; the bucket, database, env, and URL stay. Ignored otherwise |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| note | No | ||
| team | No | ||
| tier | Yes | ||
| start | No | ||
| status | Yes | ||
| renamed | No | ||
| project_id | Yes | ||
| machine_url | No | ||
| teardown_at | No |