Overview
Core concepts — base URLs, authentication, error format, and site identifiers.
Base URL
The full management API lives on a dedicated subdomain and is versioned:
https://api.static.app/v1
Postman collection
Download the ready-to-import collection with every endpoint pre-configured (auth, variables, sample bodies):
Download Postman collection (v2.1)
After import, set the apiKey variable to your key and pid to a site's public ID.
Authentication
Endpoints marked Auth require a personal API key. Create one in Account → API. Keys start with sk_. Pass the key in the Authorization header:
Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Endpoints marked Public work without a key but are scoped to a domain or request context.
Errors
The API uses standard HTTP status codes and returns JSON with status/message on errors.
| Code | Meaning |
| 200 | Success. |
| 201 | Created. |
| 204 | No content. |
| 400 | Bad request — malformed input, plan limit, invalid domain. |
| 401 | Missing, invalid, or expired credentials, or wrong page password. |
| 403 | No active team, invalid form token, plan limit exceeded. |
| 404 | Site, file, form, page, or plan not found. |
| 422 | Validation failed. |
| 429 | Rate limited. |
| 500 | Server error. |
Example error response
{
"status": "error",
"message": "Site not found"
}
Response fields
| Field | Type | Description |
status | string | Always "error" on failure. |
message | string | Human-readable explanation. |
Site identifier (pid)
Every site has a public 10-character alphanumeric identifier (e.g. 0aw4jtby1z). Use it everywhere a {pid} appears in the URL or a pid field appears in the body.
Workspaces
Workspaces (teams) group sites and members. Every request runs against your active workspace. List, inspect the current one, switch, or override per request.
List workspaces Auth
Returns every workspace you can access — ones you own and ones where you are a member.
GET /v1/workspaces
Example request
curl https://api.static.app/v1/workspaces \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"data": [
{
"pid": "xxxxxxxxxx",
"name": "My workspace",
"is_owner": true,
"is_current": true,
"is_default": true
},
{
"pid": "yyyyyyyyyy",
"name": "Side project",
"is_owner": false,
"is_current": false,
"is_default": false
}
]
}
Response fields
| Field | Type | Description |
data[].pid | string | Public workspace identifier. |
data[].name | string | Workspace display name. |
data[].is_owner | boolean | true if the authenticated user owns the workspace. |
data[].is_current | boolean | true if this is the active workspace for the authenticated user. |
data[].is_default | boolean | true if this is the user's default workspace. |
Current workspace Auth
Returns the workspace that requests run against by default.
GET /v1/workspaces/current
Example request
curl https://api.static.app/v1/workspaces/current \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"pid": "xxxxxxxxxx",
"name": "My workspace",
"is_owner": true
}
Response fields
| Field | Type | Description |
pid | string | Active workspace public identifier. |
name | string | Workspace display name. |
is_owner | boolean | true if the user owns it. |
Switch workspace Auth
Persists a new active workspace for your account. Subsequent requests use it until you switch again.
POST /v1/workspaces/switch
Body
| Name | Type | Required | Description |
pid | string | required | Public ID of the workspace to switch to. |
Example request
curl -X POST https://api.static.app/v1/workspaces/switch \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"pid":"yyyyyyyyyy"}'
Example response
{
"status": "success",
"workspace": {
"pid": "yyyyyyyyyy",
"name": "Side project"
}
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
workspace.pid | string | Public ID of the now-active workspace. |
workspace.name | string | Display name. |
Override per request
Without switching globally, run a single request against another workspace by passing X-Team-Pid header (or ?team_pid= query string):
curl https://api.static.app/v1/sites \
-H "Authorization: Bearer sk_xxxx" \
-H "X-Team-Pid: 9af1zr5w0e"
If the header is omitted, the active workspace (current_team_id, falling back to default_team_id if missing) is used.
Sites
Sites are the deployed projects in your workspace. List, create, update, and delete.
List sites Auth
Returns all sites in the active workspace.
GET /v1/sites
Example request
curl https://api.static.app/v1/sites \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"data": [
{
"pid": "xxxxxxxxxx",
"slug": "example-site",
"name": "Example Site",
"domain": "example.static.app",
"status": true,
"full_url": "https://example.static.app",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-02-01T12:30:00Z"
}
]
}
Response fields
| Field | Type | Description |
data[].pid | string | Public site identifier. |
data[].slug | string | URL slug of the site. |
data[].name | string | Site display name. |
data[].domain | string | Primary domain attached to the site. |
data[].status | boolean | true if the site is active. |
data[].full_url | string | Canonical URL of the site. |
data[].created_at | string (ISO-8601) | Creation timestamp. |
data[].updated_at | string (ISO-8601) | Last modification timestamp. |
Get site Auth
GET /v1/sites/{pid}
Path
| Name | Type | Required | Description |
pid | string | required | Public site identifier. |
Example request
curl https://api.static.app/v1/sites/xxxxxxxxxx \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"pid": "xxxxxxxxxx",
"slug": "example-site",
"name": "Example Site",
"domain": "example.static.app",
"status": true,
"full_url": "https://example.static.app",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-02-01T12:30:00Z"
}
Response fields
| Field | Type | Description |
pid | string | Public site identifier. |
slug | string | URL slug of the site. |
name | string | Site display name. |
domain | string | Primary domain attached to the site. |
status | boolean | true if active. |
full_url | string | Canonical URL. |
created_at | string (ISO-8601) | Creation timestamp. |
updated_at | string (ISO-8601) | Last modification timestamp. |
Create / update from URL Auth
Imports a site from a remote ZIP archive. Pass pid to update an existing site.
POST /v1/sites
Body
| Name | Type | Required | Description |
url | string | required | HTTPS link to a ZIP archive. |
domain | string | optional | Custom subdomain. Random if omitted. |
pid | string | optional | Update an existing site instead of creating one. |
Example request
curl -X POST https://api.static.app/v1/sites \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/site.zip","domain":"example-site"}'
Example response
{
"status": "success",
"pid": "xxxxxxxxxx",
"slug": "example-site",
"url": "https://example-site.static.app"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
pid | string | Public identifier of the created (or updated) site. |
slug | string | URL slug. |
url | string | Canonical URL of the site. |
Create / update from ZIP upload Auth
Uploads a ZIP archive directly.
POST /v1/sites/zip
Body (multipart/form-data)
| Name | Type | Required | Description |
archive | file | required | The ZIP archive. |
domain | string | optional | Custom subdomain. |
pid | string | optional | Update an existing site. |
Example request
curl -X POST https://api.static.app/v1/sites/zip \
-H "Authorization: Bearer sk_xxxx" \
-F "[email protected]" \
-F "pid=xxxxxxxxxx"
Example response
{
"status": "success",
"pid": "xxxxxxxxxx",
"slug": "example-site",
"url": "https://example-site.static.app"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
pid | string | Public identifier of the created or updated site. |
slug | string | URL slug. |
url | string | Canonical URL. |
Delete site Auth
DELETE /v1/sites/{pid}
Returns 204 No Content.
Example request
curl -X DELETE https://api.static.app/v1/sites/xxxxxxxxxx \
-H "Authorization: Bearer sk_xxxx"
Rename free domain Auth
POST /v1/sites/{pid}/rename-free-domain
Body
| Name | Type | Required | Description |
domain | string | required | New subdomain name (without TLD). |
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/rename-free-domain \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"domain":"new-example-name"}'
Example response
{
"status": "success"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
Purge CDN cache Auth
POST /v1/sites/{pid}/purge-cache
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/purge-cache \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"status": "success",
"message": "Cache purged successfully"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
message | string | Human-readable confirmation. |
Hold / unhold sites Auth
Temporarily disables (hold) or re-enables (unhold) one or more sites.
POST /v1/sites/hold
POST /v1/sites/unhold
Body
| Name | Type | Required | Description |
ids | int | int[] | required | Site ID or array of site IDs. |
Example request
curl -X POST https://api.static.app/v1/sites/hold \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"ids":[101, 102, 103]}'
Example response
{
"status": "success",
"processed": 3
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
processed | integer | Number of sites affected by the operation. |
Files
Files live inside a site. List, read, write, upload, download, and delete.
List files in a site Auth
GET /v1/sites/files/{pid}
Query
| Name | Type | Required | Description |
path | string | optional | Subdirectory. Defaults to site root. |
Example request
curl "https://api.static.app/v1/sites/files/xxxxxxxxxx?path=images" \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"status": "success",
"current_path": "",
"files": [
{
"name": "index.html",
"path": "index.html",
"is_dir": false,
"size": 1234,
"modified": 1715600000,
"type": "html",
"hash": "0123456789abcdef0123456789abcdef"
},
{
"name": "images",
"path": "images",
"is_dir": true,
"size": null,
"modified": 1715600000,
"type": "directory",
"hash": null
}
]
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
current_path | string | Directory being listed (empty string = site root). |
files[].name | string | File or directory name. |
files[].path | string | Path relative to site root. |
files[].is_dir | boolean | true for directories. |
files[].size | integer | null | Size in bytes; null for directories. |
files[].modified | integer | Last-modified Unix timestamp. |
files[].type | string | File extension or "directory". |
files[].hash | string | null | MD5 of file contents; null for directories. |
List files for multiple sites Auth
Batch version of the previous endpoint.
POST /v1/sites/files-by-pids
Body
| Name | Type | Required | Description |
pids | string[] | required | Array of site PIDs. |
Example request
curl -X POST https://api.static.app/v1/sites/files-by-pids \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"pids":["xxxxxxxxxx","yyyyyyyyyy"]}'
Example response
{
"status": "success",
"data": {
"xxxxxxxxxx": {
"status": "success",
"files": [
{
"name": "index.html",
"path": "index.html",
"is_dir": false,
"size": 1234,
"modified": 1715600000,
"type": "html",
"hash": "0123456789abcdef0123456789abcdef"
}
]
},
"yyyyyyyyyy": {
"status": "error",
"message": "Site not found"
}
}
}
Response fields
| Field | Type | Description |
status | string | "success" on the overall request. |
data[pid] | object | Per-site result, keyed by requested pid. |
data[pid].status | string | "success" if the site was resolved. |
data[pid].files | array | File entries (same shape as List files). |
data[pid].message | string | Error message when status is not "success". |
Download site as ZIP Auth
GET /v1/sites/download/{pid}
Example request
curl https://api.static.app/v1/sites/download/xxxxxxxxxx \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"status": "success",
"url": "https://static.app/storage/zip/abcdef0123456789_download.zip"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
url | string | Temporary signed URL to download the ZIP. Expires after a short window. |
Download selected files Auth
POST /v1/sites/download-files/{pid}
Body
| Name | Type | Required | Description |
files | string[] | required | Relative file paths to bundle. |
Example request
curl -X POST https://api.static.app/v1/sites/download-files/xxxxxxxxxx \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"files":["index.html","css/style.css"]}'
Example response
{
"status": "success",
"url": "https://static.app/storage/zip/abcdef0123456789_files.zip"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
url | string | Temporary signed URL to download the bundle. |
Upload files Auth
POST /v1/sites/upload-files/{pid}
Body (multipart/form-data)
| Name | Type | Required | Description |
files[] | file[] | required | One or more files. |
paths[] | string[] | optional | Destination path for each file. Defaults to site root. |
Example request
curl -X POST https://api.static.app/v1/sites/upload-files/xxxxxxxxxx \
-H "Authorization: Bearer sk_xxxx" \
-F "files[][email protected]" \
-F "files[][email protected]" \
-F "paths[]=index.html" \
-F "paths[]=css/style.css"
Example response
{
"status": "success",
"uploaded": 2,
"files": [
{ "name": "index.html", "path": "index.html", "size": 1234 },
{ "name": "style.css", "path": "css/style.css", "size": 567 }
],
"errors": []
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
uploaded | integer | Number of files successfully written. |
files[].name | string | Stored file name. |
files[].path | string | Final path relative to site root. |
files[].size | integer | Bytes written. |
errors | array | Per-file error messages for entries that failed. |
Delete files Auth
POST /v1/sites/delete-files/{pid}
Body
| Name | Type | Required | Description |
paths | string[] | required | Relative paths to delete. |
Example request
curl -X POST https://api.static.app/v1/sites/delete-files/xxxxxxxxxx \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"paths":["old.html","images/legacy.png"]}'
Example response
{
"status": "success",
"deleted": 1,
"paths": ["old.html"],
"errors": []
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
deleted | integer | Number of files successfully deleted. |
paths | string[] | Paths that were deleted. |
errors | array | Per-path error messages for entries that failed. |
Read file Auth
Returns the full contents of a single file. Served from the main domain.
POST /api/files/{pid}/read
Body
| Name | Type | Required | Description |
fileName | string | required | File name, e.g. data.csv. |
relativePath | string | optional | Directory inside the site. |
Example request
curl -X POST https://static.app/api/files/xxxxxxxxxx/read \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"fileName":"data.csv","relativePath":"public_html"}'
Example response
{
"status": "success",
"fileName": "data.csv",
"content": "id,name\n1,foo\n2,bar\n"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
fileName | string | The file that was read. |
content | string | Full file contents. |
Append / prepend to file Auth
Writes content to the top or bottom of an existing file. Designed for incremental updates such as appending CSV rows.
POST /api/files/{pid}/edit
Body
| Name | Type | Required | Description |
fileName | string | required | File to modify. |
relativePath | string | optional | Directory inside the site. |
content | string | required | Text to insert. |
position | string | required | top or bottom. |
newline | boolean | optional | Insert \n between old and new content. |
Example request
curl -X POST https://static.app/api/files/xxxxxxxxxx/edit \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"fileName":"data.csv","content":"3,baz","position":"bottom","newline":true}'
Example response
{
"status": "success",
"fileName": "data.csv",
"size": 28
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
fileName | string | The file that was modified. |
size | integer | Resulting file size in bytes. |
Forms
Forms collect submissions on a site. List forms and inspect their entries.
POST /v1/sites/{pid}/forms
Body
| Name | Type | Required | Description |
sort | string | optional | asc or desc. |
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/forms \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"sort":"desc"}'
Example response
{
"data": [
{
"pid": "zzzzzzzzzz",
"name": "Contact form",
"form_hash": "0123456789abcdef0123456789abcdef",
"entries_count": 42,
"created_at": "2025-01-15T10:00:00Z"
}
]
}
Response fields
| Field | Type | Description |
data[].pid | string | Public form identifier. |
data[].name | string | Form display name. |
data[].form_hash | string | Hash embedded in the form template. |
data[].entries_count | integer | Total submissions for this form. |
data[].created_at | string (ISO-8601) | Creation timestamp. |
POST /v1/sites/{pid}/forms/{form_id}
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/forms/42 \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"pid": "zzzzzzzzzz",
"name": "Contact form",
"form_hash": "0123456789abcdef0123456789abcdef",
"notification_email": "[email protected]",
"entries_count": 42,
"created_at": "2025-01-15T10:00:00Z"
}
Response fields
| Field | Type | Description |
pid | string | Public form identifier. |
name | string | Form display name. |
form_hash | string | Hash embedded in the form template. |
notification_email | string | Email that receives submissions. |
entries_count | integer | Total submissions. |
created_at | string (ISO-8601) | Creation timestamp. |
DELETE /v1/sites/{pid}/forms
Body
| Name | Type | Required | Description |
form_ids | int[] | required | Form IDs to delete. |
Example request
curl -X DELETE https://api.static.app/v1/sites/xxxxxxxxxx/forms \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"form_ids":[42, 43]}'
Example response
{
"status": "success",
"message": "2 forms deleted."
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
message | string | Human-readable confirmation. |
POST /v1/sites/{pid}/forms/change-email
Body
| Name | Type | Required | Description |
email | string | required | Email address to send submissions to. |
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/forms/change-email \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'
Example response
{
"status": "success"
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
POST /v1/sites/{pid}/forms/{form_id}/entries
Body
| Name | Type | Required | Description |
per_page | int | optional | Items per page. Default 20. |
sort | string | optional | asc or desc. |
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/forms/42/entries \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"per_page":20,"sort":"desc"}'
Example response
{
"data": [
{
"pid": "qqqqqqqqqq",
"page": "/contact",
"fullurl": "https://example.static.app/contact",
"ip": "203.0.113.42",
"is_spam": false,
"data": [
{ "name": "name", "value": "Jane Doe" },
{ "name": "email", "value": "[email protected]" },
{ "name": "message", "value": "Hello!" }
],
"created_at": "2025-02-01T12:34:56Z"
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"total": 42
}
}
Response fields
| Field | Type | Description |
data[].pid | string | Public entry identifier. |
data[].page | string | Page path where the form was submitted. |
data[].fullurl | string | Full submission URL. |
data[].ip | string | Submitter IP (may be empty). |
data[].is_spam | boolean | true if marked as spam. |
data[].data[].name | string | Field name. |
data[].data[].value | string | Field value. |
data[].created_at | string (ISO-8601) | Submission timestamp. |
meta.current_page | integer | Current pagination page. |
meta.per_page | integer | Page size. |
meta.total | integer | Total entries for the form. |
DELETE /v1/sites/{pid}/forms/{form_id}/entries
Body
| Name | Type | Required | Description |
entry_ids | int[] | required | Entry IDs to delete. |
Example request
curl -X DELETE https://api.static.app/v1/sites/xxxxxxxxxx/forms/42/entries \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"entry_ids":[101, 102]}'
Example response
{
"status": "success",
"message": "2 entries deleted."
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
message | string | Human-readable confirmation. |
POST /v1/sites/{pid}/forms/{form_id}/entries/mark-spam
Body
| Name | Type | Required | Description |
entry_ids | int[] | required | Entry IDs. |
Example request
curl -X POST https://api.static.app/v1/sites/xxxxxxxxxx/forms/42/entries/mark-spam \
-H "Authorization: Bearer sk_xxxx" \
-H "Content-Type: application/json" \
-d '{"entry_ids":[101]}'
Example response
{
"status": "success",
"message": "1 entries marked as spam."
}
Response fields
| Field | Type | Description |
status | string | "success" on success. |
message | string | Human-readable confirmation. |
Users
Your account profile. Read the signed-in user's details.
Get profile Auth
Returns the authenticated user's profile, current plan, and usage stats.
GET /v1/users/profile
Example request
curl https://api.static.app/v1/users/profile \
-H "Authorization: Bearer sk_xxxx"
Example response
{
"data": {
"first_name": "Jane",
"last_name": "Doe",
"email": "[email protected]",
"image": "",
"plan": {
"name": "large",
"status": "active",
"sites": 30,
"storage": 10000
},
"usage": {
"sites": 10,
"storage": 262.15
},
"sites": 10,
"limit": true,
"created_at": "2021-03-19T20:38:55Z"
}
}
Response fields
| Field | Type | Description |
data.first_name | string | User's first name. |
data.last_name | string | User's last name. |
data.email | string | User email. |
data.image | string | Avatar URL, or empty string. |
data.plan.name | string | Plan slug. |
data.plan.status | string | active, pending, or incomplete. |
data.plan.sites | integer | Site quota included in the plan. |
data.plan.storage | integer | Storage quota in megabytes. |
data.usage.sites | integer | Current site count. |
data.usage.storage | number | Current storage usage in megabytes. |
data.sites | integer | Convenience copy of usage.sites. |
data.limit | boolean | true if usage is within plan limits. |
data.created_at | string (ISO-8601) | Account creation timestamp. |