# StaticX Full LLM Context StaticX helps users create, upload, deploy, version, roll back, automate, and operate static websites. The product exposes a visual dashboard plus API, CLI, and MCP tooling for automation and AI agents. ## Canonical machine-readable files - `/llms.txt`: concise LLM index. - `/llms-full.txt`: this expanded context file. - `/openapi.json`: canonical OpenAPI 3.1 contract. - `/api/v1/openapi.json`: byte-identical alias of `/openapi.json`. - Append `.md` to any product page URL for a Markdown version (e.g. `/react-hosting.md`). ## Authentication StaticX uses scoped API tokens. Pass the token as a bearer token: ```http Authorization: Bearer STATICX_API_TOKEN Accept: application/json ``` Token values are secrets. Do not print them, log them, commit them, or include them in generated documentation. Shared examples should use placeholders such as `sx_replace_with_your_token`. ## Token scopes - Global tokens can operate across the account when the selected abilities allow it. - Workspace tokens stay inside one workspace. - Site tokens stay inside one site and are best for CI or one-agent deployment jobs. - Tokens can expire and can be revoked from StaticX settings. ## Required deployment shape - Static archives should place the published files at the archive root. - The root must contain `index.html` or `index.htm`. - The root must contain `404.html`. - Use `/projects/{project}/files` to upload files, queue ZIP archive imports, or queue URL imports. - ZIP and URL imports return `202` with `status=queued`; poll `/projects/{project}/imports/status` until `state=completed` before publishing. - Use `DELETE /projects/{project}/files` to delete workspace files or folders only after explicit user confirmation. - Use `/projects/{project}/deployments` to publish. - `versioned_history` creates a new immutable deployment per publish. - `baseline_only` updates the first/baseline release and keeps analytics/forms attached without growing history. ## Indexing (SpeedyIndex) StaticX can submit and check site URLs against search engines through SpeedyIndex. The SpeedyIndex API key belongs to the account OWNER (the site owner), is stored encrypted, is set in Settings -> Indexing, and is NEVER returned by the API. A workspace member acting on a shared site uses the owner's key and balance. Engine asymmetry (enforced server-side): - indexer: google, yandex (bing has NO indexer). - checker: google, yandex, bing. Endpoints: - `GET /indexing/balance`: the token user's SpeedyIndex balance as `{ "data": { "tokens", "indexer", "checker" } }`. No key -> 401 with error_code=no_key. - `GET /indexing/pages?engine=&status=&site=&workspace=&page=`: account-wide page inventory for every site the token can access, for one engine. Defaults: engine=google, status=unchecked. status=all returns all statuses. Response: `{ engine, status, rows[], metrics{}, trend[], pagination{} }`. Statuses: unchecked, not_indexed, pending, indexed, error, requested, not_requested. - `POST /projects/{project}/indexing/submit`: body `{ "engine": "google", "type": "indexer", "urls": ["https://..."] }`. Omit `urls` to submit the sitemap-diff set. Idempotent. Returns `{ "data": { "created", "submitted", "est_tokens" } }`. - `POST /projects/{project}/indexing/check`: body `{ "engine": "google", "urls": [...] }`. Omit `urls` to check the full site inventory. Repeatable. Returns `{ "data": { "created", "submitted" } }`. - `GET /projects/{project}/indexing/tasks`: recent tasks as `{ "data": [ ... ] }`. - `GET /projects/{project}/indexing/tasks/{task}`: one task plus its lazily fetched per-URL report. Indexing error codes (the JSON body always carries a machine-readable `error_code`): - `no_key` (HTTP 401): no SpeedyIndex key is connected. Recover: connect a key in Settings -> Indexing. - `insufficient_balance` (HTTP 402): the owner's SpeedyIndex balance is too low. Recover: top up SpeedyIndex credits. - `engine_unsupported` (HTTP 422): the engine/type combination is invalid (for example bing + indexer). Recover: choose a supported engine/type. - `rate_limited` (HTTP 429): SpeedyIndex rate limit reached. Recover: wait and retry. - `server` (HTTP 502): SpeedyIndex returned an upstream error. Recover: retry later. Authorization: indexing reads need `projects.read`; submit/check need `projects.write`. A project outside the token scope returns 403/404 like every other project route. The key is never present in any response or log. ## Plan limits and quota behavior - Free plan: 1 site, 500 MB total account storage, 500 MB maximum upload, 1,000 stored form entries, 1 team seat, last 5 rollback versions. - Plus plan: 15 sites, 10 GB storage, 50 GB maximum upload, 20,000 stored form entries, 5 team seats, last 10 rollback versions. - Pro plan: 100 sites, 20 GB storage, 50 GB maximum upload, 100,000 stored form entries, 10 team seats, last 50 rollback versions. - Unlimited plan: custom sites, storage, form entries, team seats, and rollback history, with 50 GB maximum upload. - Limits are enforced for dashboard uploads, API uploads, CLI/MCP uploads, URL imports, and hosted form submissions. - If an API response has `error_code=PLAN_QUOTA_EXCEEDED`, stop. Return the exact message and suggest cleaning up storage, deleting form entries, or upgrading. ## Golden deploy prompt Use this prompt when handing a static site deployment to an AI agent: ```text Use StaticX to deploy this static website. Before publishing: - inspect the project structure - build the site if a build step exists - confirm the publish root contains index.html or index.htm - confirm the publish root contains 404.html - explain exactly what files will be uploaded Then: - upload the build output to StaticX - if the upload response says `status=queued`, poll `/projects/{project}/imports/status` until `state=completed` before publishing - publish the site - if the user wants rollback history, keep `versioning_enabled=true` - if the user asks to avoid version history, send `versioning_enabled=false` when creating the site or deploying so StaticX keeps one baseline release only - return the live URL, deployment mode, deployment id, and any warnings Safety: - never print or log STATICX_API_TOKEN - do not delete files, rollback, or remove deployments without asking - when deleting workspace files, use DELETE /projects/{project}/files with the exact file_keys the user approved - if the API returns PLAN_QUOTA_EXCEEDED, stop and report the exact quota error - if import status becomes failed or stalled, stop and report the exact import message - if anything else fails, stop and report the exact API error ``` ## Exact curl examples Set these variables first: ```bash export STATICX_API_BASE_URL="https://staticx.site/api/v1" export STATICX_API_TOKEN="sx_replace_with_your_token" export STATICX_PROJECT_ID="123" ``` Upload a ZIP archive: ```bash curl -X POST "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/files" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -F "mode=zip" \ -F "path=" \ -F "archive=@dist.zip" ``` Poll ZIP import status before deploy: ```bash curl -X GET "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/imports/status" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" ``` Upload individual files: ```bash curl -X POST "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/files" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -F "mode=files" \ -F "path=" \ -F "files[]=@index.html" \ -F "files[]=@404.html" ``` Delete workspace files: ```bash curl -X DELETE "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/files" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"file_keys":["assets/old.xml","assets/unused-folder"]}' ``` Publish a deployment version: ```bash curl -X POST "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/deployments" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{}' ``` The publish runs in the background. Poll the deployment until it finishes: ```bash curl "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/deployments/{deployment}" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" ``` Disable deployment history and publish the baseline release only: ```bash curl -X POST "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/deployments" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"versioning_enabled":false}' ``` Re-enable deployment history for future publishes: ```bash curl -X PATCH "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"versioning_enabled":true}' ``` Read deployment history: ```bash curl "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/deployments" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" ``` Start manual custom domain setup: ```bash curl -X POST "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/domain" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"domain":"app.example.com"}' ``` Check custom domain status: ```bash curl "$STATICX_API_BASE_URL/projects/$STATICX_PROJECT_ID/domain" \ -H "Authorization: Bearer $STATICX_API_TOKEN" \ -H "Accept: application/json" ``` Domain workflow notes: - The API domain endpoint returns manual DNS instructions. - CLI command: `staticx domain --site-id SITE_ID --domain app.example.com`. - MCP tool: `staticx_connect_custom_domain`. - DNS Connect is dashboard-only because the domain owner must approve access in a browser. - If the user asks for DNS automation, tell them to open Site Settings → Domain or Settings → Publishing domain and approve DNS Connect. - If the user asks to move a generated free subdomain onto an account publishing domain, tell them to use Site Settings → Domain in the dashboard. The suffix selector is dashboard-only until a public API route exists. - Generated subdomain labels are unique per suffix, so `launch.staticx.store` and `launch.example.com` can coexist, but duplicate `launch.example.com` cannot. ## Static form rules - Add `data-staticx-form` to the `