Endpoints

API Reference

Read recent project activity.

Base URL

https://staticx.site/api/v1

Every route requires Accept: application/json and a bearer token with the ability and scope needed for that route.

Authorization: Bearer STATICX_API_TOKEN
Accept: application/json

LLM-readable contract

Give agents the schema before they call the API.

StaticX publishes a concise LLM index, a full agent context file, and an OpenAPI 3.1 document that mirrors the current /api/v1 routes. Use these files for AI agents, generated clients, internal tools, and CI automation.

curl https://staticx.site/openapi.json
curl https://staticx.site/llms-full.txt

CLI authentication

The npm CLI is a thin client over the same API.

staticx login stores the base URL and bearer token locally, then verifies access with GET /user. Every later command keeps using the same token scope and route contract shown on this page.

npm install -g staticx

staticx login --base-url "https://staticx.site/api/v1" --token "STATICX_API_TOKEN"
staticx guide
staticx whoami

Token scopes

Match the token to the job.

Global

Account-wide access for internal tools, dashboards, or broad admin automation.

Common access levels in the UI: Full access and Read only.

Site-scoped

Limited to one site. Best for CI jobs, deploy bots, and one-off agent runs.

Common access levels in the UI: Full access and Read only.

Workspace-scoped

Limited to one workspace. Best when one runner needs several sites but should stay inside one team or client boundary.

Common access levels in the UI: Full access and Read only.

The API still returns internal preset ids in current_token.preset for debugging. The dashboard shows the user-facing labels Full access and Read only.

Route index

Current versioned API contract.

Account and access

GET /user Return the authenticated user for the current token.
GET /workspaces List workspaces visible to the token owner.
POST /workspaces Create a workspace. Body: name.
GET /workspaces/{workspace} Read a workspace with members and project count.
DELETE /workspaces/{workspace} Delete a workspace. Body: site_action=move/delete, target_workspace_id when moving.
GET /domains List visible custom domains and generated subdomains.

Projects

GET /projects List projects visible to the token owner. Optional query: workspace_id.
POST /projects Create a project. Body: workspace_id, name, description, archive, or source_url.
GET /projects/{project} Read one project, including workspace, host, status, and public URL.
PATCH /projects/{project} Update project metadata. Body: name, description.
DELETE /projects/{project} Delete a project the token owner can write to.
POST /projects/{project}/domain Move a project to a custom domain. Body: domain. Returns the DNS record to create.
GET /projects/{project}/domain Read custom domain status, DNS instructions, and SSL activation state.

Files and imports

GET /projects/{project}/files List workspace files. Optional query: path.
POST /projects/{project}/files Upload files, upload a ZIP, or queue URL import. Body depends on mode.

Deployments

GET /projects/{project}/deployments List published deployment versions for the project.
POST /projects/{project}/deployments Publish the current project state as an immutable deployment. Requires a root index.html or index.htm and 404.html.
GET /projects/{project}/deployments/{deployment} Read one published deployment version.
POST /projects/{project}/deployments/{deployment}/rollback Activate a previous successful immutable deployment.
DELETE /projects/{project}/deployments/{deployment} Delete one inactive deployment record. Active deployments are protected.
DELETE /projects/{project}/deployments/delete-selected Delete multiple inactive deployments. Body: deployment_ids[].

Environment and logs

GET /projects/{project}/environment-variables List project variables.
POST /projects/{project}/environment-variables Create one variable. Body: key, value, is_secret.
PUT /projects/{project}/environment-variables Replace/sync variables. Body: variables[].
DELETE /projects/{project}/environment-variables/{environmentVariable} Delete one variable.
GET /projects/{project}/logs Read recent project activity.

Current token

Read the active token context with /user.

{
  "data": {
    "id": 18,
    "name": "Amina Hart",
    "email": "[email protected]",
    "current_token": {
      "id": 44,
      "name": "Morning Peak deploy bot",
      "kind": "project",
      "preset": "project_editor",
      "preset_label": "Full access",
      "scope_type": "project",
      "scope_id": 81,
      "scope_label": "Site ยท Morning Peak",
      "abilities": [
        "user.read",
        "projects.read",
        "projects.write",
        "files.read",
        "files.write",
        "deploy.read",
        "deploy.run",
        "logs.read"
      ],
      "expires_at": "2026-05-22T10:00:00+00:00"
    }
  }
}

Command mapping

What the public CLI is expected to call.

CLI command API routes Notes
staticx login GET /user Stores the token client-side and confirms the current token metadata.
staticx workspaces GET /workspaces Best with a Global token because it may cross workspace boundaries.
staticx sites --workspace-id WORKSPACE_ID GET /projects?workspace_id=... Best with a Workspace token when the job should stay inside one workspace.
staticx create --workspace-id ... --name "Site" POST /projects Creates a site inside the given workspace.
staticx deploy --site-id SITE_ID --dir dist POST /projects/{project}/files, POST /projects/{project}/deployments Upload, then publish a new version. Best with a Site token.
staticx domain --site-id SITE_ID --domain app.example.com POST /projects/{project}/domain Move a site to a custom domain and return the DNS record to create.
staticx domain-status --site-id SITE_ID GET /projects/{project}/domain Read domain activation progress after the DNS record is created.
staticx logs --site-id SITE_ID GET /projects/{project}/logs Use after uploads, builds, and deployments.

Custom domain setup

One API call, one DNS record.

This is the API version of the dashboard domain setup. Send the domain you want, copy the DNS record from the response, and StaticX handles the rest automatically.

curl -X POST "https://staticx.site/api/v1/projects/81/domain" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"domain":"app.example.com"}'

curl "https://staticx.site/api/v1/projects/81/domain" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Project creation

Create an empty site, a ZIP-backed site, or a URL import.

Empty project

Create a blank site first, then upload files or deploy content later.

curl -X POST "https://staticx.site/api/v1/projects" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"Marketing Site"}'

Create from ZIP

Start the site with a ready-built archive when the project already exists locally.

curl -X POST "https://staticx.site/api/v1/projects" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -F "name=Marketing Site" \
  -F "[email protected]"

Create from URL

Queue a remote import when STATICX should mirror a public site for you.

curl -X POST "https://staticx.site/api/v1/projects" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -F "source_url=https://example.com"

File upload modes

Use one endpoint for files, ZIP archives, and URL imports.

Mode Required fields Use case
files files[], optional path, optional overwrite_confirmed Upload one or more files into a project path.
zip archive, optional path, optional overwrite_confirmed Upload a built static site. The ZIP root should contain index.html or index.htm plus 404.html.
url source_url, optional path Queue an import from a public URL.
curl -X POST "https://staticx.site/api/v1/projects/{project}/files" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -F "mode=zip" \
  -F "overwrite_confirmed=1" \
  -F "[email protected]"

Deploy

Upload first, publish second.

# The uploaded ZIP must include index.html or index.htm plus 404.html at the root.
curl -X POST "https://staticx.site/api/v1/projects/{project}/deployments" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

If the deployment fails, stop and return the API message plus project logs. Do not report success unless the deployment response has status=succeeded.

Deployment versioning

Rollback changes the active release pointer.

Successful deployments created by the current publisher include a readable release name, versioning state, active state, file count, and size. Rollback never copies files; it activates an existing deployment.

Rollback

curl -X POST "https://staticx.site/api/v1/projects/{project}/deployments/{deployment}/rollback" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Delete one inactive deployment

curl -X DELETE "https://staticx.site/api/v1/projects/{project}/deployments/{deployment}" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Delete selected deployments

curl -X DELETE "https://staticx.site/api/v1/projects/{project}/deployments/delete-selected" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"deployment_ids":[101,102]}'

The API rejects deletion of the active deployment. Publish another release or roll back first, then delete inactive versions.

Environment variables

Store per-project settings for automation.

Create one variable

curl -X POST "https://staticx.site/api/v1/projects/{project}/environment-variables" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"key":"PUBLIC_API_URL","value":"https://api.example.com","is_secret":false}'

Sync variables

curl -X PUT "https://staticx.site/api/v1/projects/{project}/environment-variables" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"variables":[{"key":"TOKEN","value":"secret","is_secret":true}]}'

Responses

Predictable JSON shapes.

Project response

{
  "data": {
    "id": 18,
    "name": "Marketing Site",
    "description": "Production landing pages",
    "host": "marketing.example.test",
    "public_url": "https://marketing.example.test",
    "status": "active",
    "workspace": {
      "id": 3,
      "name": "Personal Workspace",
      "role": "owner"
    },
    "subdomain": "marketing",
    "custom_domain": null,
    "created_at": "2026-05-11T12:10:44+00:00",
    "updated_at": "2026-05-11T12:10:45+00:00"
  }
}

Deployment response

{
  "data": {
    "id": 245,
    "version_name": "Release #245",
    "version_summary": "Versioned release - live now",
    "kind": "deploy",
    "status": "succeeded",
    "message": "Deployment published.",
    "is_active": true,
    "is_versioned": true,
    "file_count": 128,
    "size_bytes": 934122,
    "created_at": "2026-06-02T10:00:00+00:00",
    "activated_at": "2026-06-02T10:00:01+00:00"
  }
}

Validation error

{
  "message": "Validation failed",
  "errors": {
    "source_url": [
      "The source url field must be a valid URL."
    ]
  }
}