Deplo
Integrations

REST API

Full reference for the deplo.sh HTTP API.

Why use the REST API?

The REST API is the universal integration layer for deplo.sh. Use it when you need deployment from any language or environment — Python, Go, Rust, Ruby, or a plain curl command:

  • Language-agnostic — any HTTP client works. No SDK installation required
  • Full platform access — every feature (deploy, projects, tokens, members) is available via REST
  • Custom integrations — build your own agent framework, webhook handler, or deployment pipeline
  • The underlying layer — the CLI, SDK, and MCP server all use this API internally

When to use the REST API vs. other methods:

Use the REST API when...Use something else when...
Your agent is in Python, Go, Rust, or another non-JS languageYou're in TypeScript/Node.js → use the SDK for type safety
You need full control over HTTP requestsYou want a one-liner → use the CLI
You're building a custom integration or webhookYou're using Claude/Cursor → use the MCP server

deplo.sh vs. building your own hosting

# ❌ Without deplo.sh: S3 + CloudFront + ACM + Route53 + IAM policies...
aws s3 cp report.html s3://my-bucket/reports/index.html
aws cloudfront create-invalidation --distribution-id E123 --paths "/*"
# Plus: bucket policies, CORS, TLS certificates, DNS records...

# ✅ With deplo.sh: one POST
curl -X POST https://api.deplo.sh/v1/deployments \
  -H "Authorization: Bearer sk_live_xxx" \
  -d '{ "project_slug": "report", "files": [{"path":"index.html","content":"<h1>Done</h1>"}] }'
# → { "url": "https://report.deplo.sh" }

Base URL: https://api.deplo.sh

All endpoints require an sk_live_ API token:

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx

When calling from the web dashboard (JWT auth), also include the workspace header:

Authorization: Bearer <jwt>
X-Workspace-Id: <workspaceId>

Token context

Get current token info

Returns workspace and scope context for the authenticated API token.

GET /v1/me
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx

Response (200):

{
  "workspaceId": "ws_abc123",
  "tokenId": "tok_abc123",
  "scopes": ["deploy"],
  "projectId": null
}

Workspaces

List workspaces

GET /workspaces

Get workspace

GET /workspaces/:workspaceId

Projects

List projects

GET /projects

Create project

POST /projects
Content-Type: application/json

{
  "name": "Weekly Report",
  "slug": "weekly-report",
  "type": "static_file",
  "default_ttl": "7d",
  "gate_type": "none"
}

gate_type accepts "none" (default, public), "password" (password-protected), or "email" (captures visitor emails as leads). When gate_type is "password", also pass "password": "<plain-text>".

Get project

GET /projects/:projectId

Update project

PATCH /projects/:projectId
Content-Type: application/json

{
  "custom_domain": "reports.acme.com"
}

To enable a password gate:

PATCH /projects/:projectId
Content-Type: application/json

{
  "gate_type": "password",
  "password": "s3cr3t"
}

To enable an email gate (lead capture):

PATCH /projects/:projectId
Content-Type: application/json

{
  "gate_type": "email"
}

To remove the gate (make project public):

PATCH /projects/:projectId
Content-Type: application/json

{
  "gate_type": "none"
}

Delete project

DELETE /projects/:projectId

Verify custom domain

POST /projects/:projectId/verify-domain

Gate leads

When a project uses gate_type: "email", visitor emails are stored as encrypted leads. Retrieve them via:

List leads for a project

GET /projects/:projectId/gate/leads?page=1&limit=20

Query parameters:

ParameterDefaultDescription
page1Page number
limit20Results per page (max 100)
searchFilter leads whose email contains this value

Response (200):

{
  "data": [
    { "id": "lead_abc123", "email": "[email protected]", "capturedAt": "2026-04-07T12:00:00.000Z" }
  ],
  "meta": { "total": 42, "page": 1, "limit": 20, "totalPages": 3 }
}

List leads across all projects

GET /projects/gate/leads?page=1&limit=25&projectId=<projectId>&search=<query>

Returns the same paginated response, enriched with projectId, projectName, and projectSlug per lead.


Deployments

Lazy deploy (auto-creates project)

Requires an sk_live_ token with deploy scope. Creates the project automatically if the slug doesn't exist.

POST /v1/deployments
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "project_slug": "weekly-report",
  "type": "static_file",
  "files": [
    { "path": "index.html", "content": "<h1>Hello</h1>", "encoding": "utf8" }
  ],
  "ttl": "7d"
}

Response (201):

{
  "id": "dep_abc123",
  "url": "https://weekly-report.deplo.sh",
  "version": 3,
  "size_bytes": 4096,
  "expires_at": "2026-04-07T12:00:00.000Z"
}

Create deployment for existing project

POST /projects/:projectId/deployments
Content-Type: application/json

{
  "type": "static_file",
  "files": [
    { "path": "index.html", "content": "<h1>Hello</h1>", "encoding": "utf8" }
  ],
  "ttl": "7d"
}

List deployments

GET /projects/:projectId/deployments

Get deployment

GET /projects/:projectId/deployments/:deploymentId

Promote deployment (rollback)

PATCH /projects/:projectId/deployments/:deploymentId/promote

Archive deployment

PATCH /projects/:projectId/deployments/:deploymentId/archive

Access Tokens

List tokens

GET /access-tokens

Create token

POST /access-tokens
Content-Type: application/json

{
  "name": "CI Deploy",
  "scopes": ["deploy"],
  "expires_at": "2027-01-01T00:00:00.000Z"
}

Response (201):

{
  "id": "tok_abc123",
  "name": "CI Deploy",
  "token": "sk_live_xxxxxxxxxxxxxxxx",
  "scopes": ["deploy"],
  "prefix": "sk_live_xxxx",
  "expires_at": null
}

Caution: The token field is returned only in this response. It cannot be retrieved again.

Revoke token

DELETE /access-tokens/:tokenId

Members

List members

GET /workspaces/:workspaceId/members

Invite member

POST /workspaces/:workspaceId/members
Content-Type: application/json

{ "email": "[email protected]", "role": "viewer" }

Remove member

DELETE /workspaces/:workspaceId/members/:memberId

Error responses

StatusMeaning
400Validation error — check the message field
401Missing or invalid token
403Token lacks required scope
404Resource not found
409Slug already taken
402Quota exceeded for your plan
413File too large
500Internal server error

What's next?

On this page