Ship API
The REST API that powers all ShipStatic interfaces. Everything the Web, CLI, and SDK can do, the API can do directly.
https://api.shipstatic.com
Authentication
Anonymous deploys work without authentication — the response includes a claim URL the user can visit to keep the site permanently. For permanent deploys and management operations, pass an API Key or a deploy token in the Authorization header. The prefix determines the credential type:
| Method | Format | Use case |
|---|---|---|
| API key | Bearer ship-{64 hex} |
Persistent access, full account |
| Deploy token | Bearer token-{64 hex} |
Scoped to deploys, optional TTL |
When both are present, the deploy token takes precedence.
Endpoints
Deployments
| Method | Path | Description |
|---|---|---|
POST |
/deployments |
Upload a new deployment (multipart) |
GET |
/deployments |
List all deployments (paginated) |
GET |
/deployments/:id |
Get deployment details |
PATCH |
/deployments/:id |
Update labels |
DELETE |
/deployments/:id |
Delete deployment (async) |
POST /deployments accepts an optional password field (6–128 characters) to protect the deployment with an unlock page. The plaintext is hashed with SHA-256 server-side; only the hash is stored. Deployment responses expose password: boolean indicating whether protection is active.
Domains
| Method | Path | Description |
|---|---|---|
PUT |
/domains/:name |
Create, link, switch, or label (upsert) |
GET |
/domains |
List all domains (paginated) |
GET |
/domains/:name |
Get domain details |
DELETE |
/domains/:name |
Delete domain |
POST |
/domains/:name/validate |
Pre-flight availability check |
POST |
/domains/:name/verify |
Trigger DNS verification |
GET |
/domains/:name/dns |
DNS provider for the domain (Cloudflare, Namecheap, etc.) |
GET |
/domains/:name/records |
Required DNS records |
GET |
/domains/:name/share |
Shareable DNS setup hash |
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 |
/config is a 301 alias for /limits, kept for older CLI versions.
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-...' \
-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 nextCursor when more pages exist. Pass it as cursor to fetch the next page.
curl -H 'Authorization: Bearer ship-...' \
'https://api.shipstatic.com/deployments?limit=50'
{
"deployments": [...],
"nextCursor": "eyJpZCI6ImhhcHB5LWNhdC1hYmMxMjM0In0"
}
Custom domain — full flow
# 1. Validate the name
curl -X POST -H 'Authorization: Bearer ship-...' \
https://api.shipstatic.com/domains/www.example.com/validate
# 2. Create + link to a deployment
curl -X PUT -H 'Authorization: Bearer ship-...' \
-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-...' \
https://api.shipstatic.com/domains/www.example.com/records
# 4. After configuring DNS, trigger verification
curl -X POST -H 'Authorization: Bearer ship-...' \
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-...' \
-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/:id (async cleanup) |
400 |
Validation error | Invalid input, missing fields |
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 |
413 |
Payload too large | Bundle exceeds plan limits |
422 |
Business rule | Resource state doesn't allow this operation |
429 |
Rate limited | Too many requests; retry after Retry-After seconds |
Pagination
List endpoints (/deployments, /domains, /tokens, /activities) return cursor-paginated results:
{ "deployments": [...], "nextCursor": "..." }
Pass the cursor as ?cursor=... to fetch the next page. nextCursor is absent on the final page. Default page size is 50; pass ?limit=N to override (capped at 100).
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.
Conventions
Content type. All requests and responses use application/json, except deployment upload which uses 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 return a consistent shape:
{
"error": "not_found",
"message": "Deployment not found",
"status": 404
}
error is the type tag (e.g. validation_failed, not_found, forbidden, rate_limit). message is the human-readable description. Some errors include a details object with structured context.