Sitelet https://docs.shipstatic.com/api
ShipStatic Docs llms.txt llms-full.txt

Publish with no credentials at all, or authenticate for everything else. This is the API behind every other interface — anything the Web, CLI and SDK can do, you can do directly.

https://api.shipstatic.com

Deploy to your account

Deploying needs no account — POST /deployments with no Authorization header works, and the response carries a claim URL the user can visit to keep the site permanently. Everything else needs a credential: pass an API Key or a deploy token in the Authorization header. The prefix says which it is:

Method Format Use case
API key Bearer ship-{32 hex} Persistent access, full account
Deploy token Bearer deploy-{32 hex} Scoped to deploys, optional TTL

One slot takes either — the prefix is what tells the two apart, so there is no precedence to reason about.

Endpoints

Deployments

Method Path Description
POST /deployments Upload a new deployment (multipart)
GET /deployments List all deployments (paginated)
GET /deployments/:deployment Get deployment details
PATCH /deployments/:deployment Update labels
DELETE /deployments/:deployment Delete deployment (async)

POST /deployments accepts an optional password field (6–128 characters) to protect the deployment with an unlock page. Passwords are handled securely server-side and can never be read back through the API. Deployment responses expose password: boolean indicating whether protection is active.

Domains

Method Path Description
PUT /domains/:domain Create, link, switch, or label (upsert)
GET /domains List all domains (paginated)
GET /domains/:domain Get domain details
DELETE /domains/:domain Delete domain
POST /domains/validate Pre-flight availability check (name in the body)
POST /domains/:domain/verify Trigger DNS verification
GET /domains/:domain/dns Which DNS provider hosts the domain (Cloudflare, Namecheap, …)
GET /domains/:domain/records The DNS records you need to add
GET /domains/:domain/share Shareable DNS setup link

Tokens

Method Path Description
POST /tokens Create token (full secret returned only here)
GET /tokens List all tokens (short identifiers only)
DELETE /tokens/:token Revoke token

Account

Method Path Description
GET /account Get current account
POST /account/claim Claim a public deployment with a claim hash
GET /activities Account audit log (paginated)
GET /labels Distinct labels in use across the account
GET /limits Plan-based platform limits (max file size, file count, total size)
GET /ping Health check

Plans

Method Path Description
GET /plans The plan menu: every plan on sale, with its price and caps. Public, no credential. Its fields are described under Plans

Examples

Anonymous public deploy

curl -X POST https://api.shipstatic.com/deployments \
  -F 'files[]=@dist/index.html' \
  -F 'files[]=@dist/styles.css' \
  -F 'checksums=["d41d8cd98f00b204e9800998ecf8427e","..."]'

Response (201):

{
  "deployment": "happy-cat-abc1234",
  "url": "https://happy-cat-abc1234.shipstatic.com",
  "claim": "https://my.shipstatic.com/claim/...",
  "files": 2,
  "size": 4321,
  "status": "success",
  "password": false,
  "via": "sdk",
  "created": "...",
  "expires": "..."
}

claim and expires are present only on anonymous deploys. Visiting claim while signed in transfers the deployment to your account.

Authenticated deploy

curl -X POST https://api.shipstatic.com/deployments \
  -H 'Authorization: Bearer ship-your-api-key' \
  -F 'files[]=@dist/index.html' \
  -F 'checksums=["d41d8cd98f00b204e9800998ecf8427e"]' \
  -F 'labels=["production"]' \
  -F 'password=hunter22'

Response is the same shape minus claim and expires.

List with pagination

List endpoints return a cursor, which is null on the last page. Pass a non-null one back as ?cursor= to fetch the next page.

curl -H 'Authorization: Bearer ship-your-api-key' \
  'https://api.shipstatic.com/deployments?limit=50'
{
  "deployments": [...],
  "cursor": "eyJpZCI6ImhhcHB5LWNhdC1hYmMxMjM0In0"
}

Custom domain — full flow

# 1. Validate the name
curl -X POST -H 'Authorization: Bearer ship-your-api-key' \
  https://api.shipstatic.com/domains/www.example.com/validate

# 2. Create + link to a deployment
curl -X PUT -H 'Authorization: Bearer ship-your-api-key' \
  -H 'Content-Type: application/json' \
  -d '{"deployment":"happy-cat-abc1234"}' \
  https://api.shipstatic.com/domains/www.example.com

# 3. Get required DNS records
curl -H 'Authorization: Bearer ship-your-api-key' \
  https://api.shipstatic.com/domains/www.example.com/records

# 4. After configuring DNS, trigger verification
curl -X POST -H 'Authorization: Bearer ship-your-api-key' \
  https://api.shipstatic.com/domains/www.example.com/verify

Claim a public deployment

curl -X POST https://api.shipstatic.com/account/claim \
  -H 'Authorization: Bearer ship-your-api-key' \
  -H 'Content-Type: application/json' \
  -d '{"claim":"<claim-hash-from-deploy-response>"}'

Returns the claimed deployment, now bound to your account.

Multipart upload shape (POST /deployments)

Field Type Notes
files[] File parts One per file. The filename carries the path (webkitRelativePath style)
checksums JSON-encoded string[] One MD5 per file, in the same order as files[]
labels JSON-encoded string[] Optional
password string Optional, 6–128 characters
via string Optional origin tag (cli, sdk, mcp, etc.)

Status Codes

Code Meaning Example
200 Success Read, update, synchronous delete
201 Created POST /deployments, POST /tokens
202 Accepted DELETE /deployments/:deployment (async cleanup)
400 Bad request Invalid input, missing fields, or a request the platform refuses
401 Authentication error Missing or invalid credentials
403 Forbidden Account terminated, plan limit reached, operation not permitted
404 Not found Resource doesn't exist or belongs to another account
409 Conflict A domain already taken, a domain operation already in progress, a deployment a domain still points at
413 Payload too large Bundle exceeds plan limits
415 Unsupported media type A deploy sent as neither multipart/form-data nor application/json
422 Unprocessable The project failed to build, or the resource's state doesn't allow this operation
429 Rate limited Too many requests; retry after Retry-After seconds
500 Server error Something failed on our side
503 Unavailable The platform is in maintenance, or a service it depends on is briefly unavailable

Errors

Every error answers the same shape:

{
  "error": "not_found",
  "message": "Deployment not found",
  "status": 404
}

error is the type tag, and one of these:

Tag Status Meaning
validation_failed 400 The input is malformed
authentication_failed 401 Credentials are missing or invalid
forbidden 403 Authenticated, but not allowed to do this
not_found 404 The resource doesn't exist, or isn't yours
rate_limit_exceeded 429 Too many requests; wait Retry-After seconds
business_logic_error 400, 409, 413, 415, 422 Well formed, but the platform refuses it; the message says why
build_failed 422 The project could not be built. details.log carries the tail of the build output. Fix the project; retrying gives the same answer
maintenance 503 The platform is closed on purpose. The message says when it reopens, so wait rather than retrying in a loop
internal_server_error 500, 503 Something failed on our side; a later retry may succeed

message is written for the person using your tool, so show it as it is. Some errors add a details object with structured context.

Branch on error and status, never on the message text. Messages are rewritten for clarity; the tag and the status are the contract.

Pagination

List endpoints (/deployments, /domains, /tokens, /activities) return cursor-paginated results:

{ "deployments": [...], "cursor": "..." }

Pass the cursor as ?cursor=... to fetch the next page. cursor is always present, and null on the final page. Default page size is 50; pass ?limit=N to override (capped at 300).

Rate Limits

Per-account global limiter; deploy endpoints additionally limited per-credential to prevent abuse. On exhaustion, the API returns 429 with a Retry-After header (seconds). Anonymous public deploys have a tighter per-IP limit than authenticated requests.

Idempotent Deploys

Deploy endpoints accept an optional Idempotency-Key header (up to 256 characters — a UUID is a good choice). If a request with a key succeeds and is retried within 24 hours, the API replays the original 201 response instead of creating a duplicate deployment; replayed responses carry Idempotency-Replay: true. Use it whenever your client retries on timeout. Failed attempts are not stored — retrying after an error runs the deploy fresh.

Conventions

Content type. All requests and responses use application/json. Deployment upload also accepts multipart/form-data.

Domain names in paths are URL-encoded. The API normalizes casing and Unicode (e.g. Example.COM → example.com).

Async operations. Only deployment deletion is asynchronous (returns 202). All other deletes are synchronous (200).

Errors share one shape and one set of tags; see Errors.