Docs / Reference
The HTTP API
Read and change your servers over HTTP with an API key: its address, pages, refusals and every route.
Sokie's HTTP API lets a script, CI or any tool that speaks HTTP read your servers and act on them, with an API key. It answers at:
https://api.sokie.cloud/v1
Its OpenAPI document is at https://api.sokie.cloud/v1/openapi.json, and needs no key to read. Every operation in it has a name, like listServers, and says the permission it needs.
For an agent, connect Sokie's own MCP server instead: Manage Sokie from your agent has the steps.
Send your key
Make an API key, then send it as a bearer token on every request:
curl https://api.sokie.cloud/v1/servers \ -H "Authorization: Bearer sokie_ak_…"
The API acts as you, with only the permissions and servers the key was given. Sokie checks the key on every call, so one you revoke, or one that expires, is refused from its next call. A key works in one workspace: to reach another, use a key from there.
Find a server
Most paths take a server's id, not its slug. Get it once from the slug:
curl https://api.sokie.cloud/v1/servers/majestic-lobster-123 \ -H "Authorization: Bearer sokie_ak_…"
The answer's serverId is what /servers/{serverId}/… takes. GET /servers lists every server the key can see, each with its id.
What it covers
| Area | Method and path | What it does | The key needs |
|---|---|---|---|
| Account | GET /me | Who the key acts for | Any key |
| Servers | GET /servers | List servers, newest first | Servers: Read |
| Servers | GET /servers/{slug} | One server, with its serverId | Servers: Read |
| Deploys | GET /servers/{serverId}/deploys | A server's deploys, newest first | Deploys: Read |
| Deploys | GET /servers/{serverId}/deploys/{number} | One deploy by its number | Deploys: Read |
| Deploys | GET /deploys/{deploymentId} | One deploy by its id, to follow a redeploy or restore | Deploys: Read |
| Deploys | POST /servers/{serverId}/redeploy | Build the live deploy's source again | Deploys: Read and write |
| Deploys | GET /servers/{serverId}/deploys/{number}/restore | What restoring a deploy would do, changing nothing | Deploys: Read |
| Deploys | POST /servers/{serverId}/deploys/{number}/restore | Restore an earlier deploy | Deploys: Read and write |
| Tools | GET /servers/{serverId}/tools | The tools production serves | Tools: Read |
| Tools | GET /servers/{serverId}/tools/{name} | One tool, with its inputs | Tools: Read |
| Tools | GET /servers/{serverId}/skills | The skills production serves | Tools: Read |
| Tools | GET /servers/{serverId}/skills/{name} | One skill | Tools: Read |
| Tools | POST /servers/{serverId}/tools/{name}/description/pull-request | Open a pull request that changes a tool's description | Tools: Read and write |
| Tools | POST /servers/{serverId}/tools/{name}/description/deploy | Change a tool's description and deploy it | Tools: Read and write |
| Logs and usage | GET /servers/{serverId}/logs | A server's calls, newest first | Logs and usage |
| Logs and usage | GET /usage | The workspace's calls this month | Logs and usage |
| Logs and usage | GET /audit | The workspace's changes from the last year | Audit trail |
| Secrets | GET /servers/{serverId}/secrets | A server's secret names, never their values | Secrets: Read |
A tool's description changes one of two ways. On a server linked to a repository, use pull-request: production changes when it merges. On one with no repository, use deploy, and send the server's liveDeploymentId as base. If production has moved on since, nothing changes and the answer says STALE_BASE.
/logs takes errors=true for only the calls that didn't succeed, and tool for one tool's. /audit takes serverId for one server's changes, and category for one kind. Logs say what happened in each call, never what was sent. Deploying new source, setting secrets and deleting servers stay with the CLI and the app.
Pages
A list comes back a page at a time:
{ "page": [ … ], "isDone": false, "continueCursor": "…" }limit sets how many to a page, 25 unless you say, and 100 at most. While isDone is false, send continueCursor back as cursor for the next page:
curl "https://api.sokie.cloud/v1/servers?limit=100&cursor=…" \ -H "Authorization: Bearer sokie_ak_…"
A query parameter a path doesn't take is refused, so a misspelled filter never reads as applied.
When it's refused
A refusal comes back as JSON, with a code and a sentence that says what to do:
{
"error": {
"code": "SCOPE_REQUIRED",
"message": "The API key “GitHub Actions” can’t deploy on Petstore: it needs Deploys, read and write.",
"scope": "deploys:write",
"server": "majestic-lobster-123"
}
}The codes are the ones the CLI shows. The status says what kind of refusal it is:
| Status | Code | What it means |
|---|---|---|
| 400 | BAD_REQUEST | A parameter or the body isn't what the path takes |
| 401 | UNAUTHENTICATED or invalid_grant | No key, or one that's unknown, expired or revoked |
| 403 | SCOPE_REQUIRED | The key lacks the permission; scope names it |
| 404 | NOT_FOUND | Nothing by that id or name, or the key wasn't given that server |
| 405 | METHOD_NOT_ALLOWED | The path doesn't take that method; Allow lists the ones it does |
| 409 | Any other code | It can't happen as things are, like DEPLOY_IN_PROGRESS while a deploy runs |
| 429 | RATE_LIMITED | Too many changes this minute; try again shortly |
| 500 | INTERNAL | A wrong id or cursor, or a fault on Sokie's side |
| 503 | UNAVAILABLE | Sokie isn't answering right now; try again shortly |
A server the key wasn't given is answered as if it weren't there, with a 404.
Limits
Changing tool descriptions, through either path, is limited to 10 a minute for each person. Past that, the call is refused with a 429 and RATE_LIMITED. One production deploy runs on a server at a time, so a redeploy or restore while another runs answers DEPLOY_IN_PROGRESS.