Quickstart
1. Get an API key
API keys are created in the dashboard, not through the API.
- Sign in to the dashboard — enter your email and we send you a six-digit code. There is no password.
- Go to API keys and click Generate new key.
- Copy the key from the dialog.
Once you are signed in, the examples on these pages carry your own key rather than a placeholder, and each one says so underneath. Copy an example and run it without editing anything first.
2. List your servers
Send the key as a bearer token:
curl https://braesystems.com/api/v1/servers \
-H "Authorization: Bearer bs_live_..."{
"data": [
{
"id": "9f1c7d2e-4a3b-4c5d-8e6f-0a1b2c3d4e5f",
"name": "kelp-01",
"status": "active",
"model": "PowerEdge R760xa",
"project_id": "3c2b1a09-8d7e-4f6a-9b8c-7d6e5f4a3b2c",
"image": "ubuntu-24-04",
"ipv4": [
{
"address": "203.0.113.11",
"version": 4,
"kind": "public"
}
],
"ipv6": [
{
"address": "2001:db8:1::11",
"version": 6,
"kind": "public"
}
],
"created_at": "2026-07-01T09:00:00.000Z"
}
]
}IPv4 and IPv6 come back as separate arrays. Most callers want one family or the other, and filtering
a mixed list by version is easy to get wrong — a v6-only host reads as having no address at all.
3. Reboot a server
Power operations do not complete within the request. You get an action back immediately and poll it:
curl -X POST https://braesystems.com/api/v1/servers/$SERVER_ID/reboot \
-H "Authorization: Bearer bs_live_..."{
"data": {
"id": "6b5a4c3d-2e1f-4a9b-8c7d-6e5f4a3b2c1d",
"server_id": "9f1c7d2e-4a3b-4c5d-8e6f-0a1b2c3d4e5f",
"kind": "reboot",
"status": "queued",
"error": null,
"simulated": false,
"created_at": "2026-07-29T14:03:11.000Z",
"completed_at": null
}
}Then poll until status is succeeded or failed:
curl https://braesystems.com/api/v1/actions/$ACTION_ID \
-H "Authorization: Bearer bs_live_..."A reboot starts as a graceful restart. If the operating system does not bring the machine back, we
escalate to a forced restart and, failing that, mark the action failed with the reason.
A note on the examples
Every example above is generated from the same schemas the API validates against, so it cannot describe a request the service would reject.
Two things they leave to you:
- The key is inline. That makes an example runnable exactly as copied. Move it to an environment variable before it reaches a file you commit.
- Ids come from the environment.
SERVER_IDand its siblings name resources in your account, which these pages have no way to know. Export one, or paste the id in place of the variable.
The Python examples use requests (pip install requests). The
TypeScript, JavaScript, and Go examples use only what the runtime already ships.
Hand it to an AI agent
If an agent is doing the integration, give it this instead of a link. It is the whole contract — endpoints, response shape, and the four or five things that are easy to get wrong — in the order an agent needs them.
You are integrating the Brae Systems API into our codebase.
Base URL: https://braesystems.com/api/v1
Auth: every request needs an `Authorization: Bearer <key>` header. Keys are
created in the Brae dashboard. One key acts on exactly one project.
Endpoints:
GET /servers list servers
GET /servers/{id} one server
GET /servers/{id}/ips that server's addresses, as one flat list
POST /servers/{id}/reboot -> 202 and an action
POST /servers/{id}/reimage body {"image": "<slug>", "ssh_key_ids": ["<id>"]}
ssh_key_ids is optional; omit it to install every
key on the account. -> 202 and an action
GET /actions/{id} poll an action
GET /images image slugs accepted by reimage
GET /projects list projects
POST /projects body {"name": "...", "kind": "production"|"development"}
GET /ssh-keys list the account's SSH keys
POST /ssh-keys body {"name": "...", "public_key": "ssh-ed25519 ..."}
DELETE /ssh-keys/{id} -> 204, no body
Rules to follow:
- Every success body is wrapped: {"data": ...}, for a single resource as much
as for a collection. Read `data`, never the root. The one exception carries
no body at all: DELETE /ssh-keys/{id} answers 204.
- A server carries `ipv4` and `ipv6` as two separate arrays. Do not concatenate
them and filter by `version` later; a v6-only host then reads as having no
address at all.
- Reboot and reimage do not finish inside the request. Both answer 202 with an
action; poll GET /actions/{id} about every 10 seconds until `status` is
`succeeded` or `failed`. On failure the reason is in `error`.
- Reimaging erases every disk on the server, with no undo. Never call it unless
the instruction names the server and says to reimage it.
- Adding an SSH key changes no running server. Keys are installed during a
reimage and at no other point.
- Errors are RFC 9457 problem documents (`application/problem+json`) carrying a
stable `type` URL. Branch on `type`. `title` and `detail` are prose and get
reworded.
- 404 means "not in your account", which covers resources that exist but belong
to someone else. Do not report it as proof that something does not exist.
- 409 means the server is busy or in a state that does not allow the operation;
retry once it settles. 429 is rate limiting; back off and retry.
- An action with `simulated: true` ran in a development project and touched no
hardware. Never report one as a real power cycle.
Read the key from an environment variable named BRAE_API_KEY. Set a request
timeout. Full documentation: https://braesystems.com/docsThat block deliberately carries no key, even when you are signed in — pasting one into an agent
sends a live credential to whoever runs the model. Tell the agent to read BRAE_API_KEY from the
environment, and put the key there yourself.
Next steps
- Managing servers — reboot and re-image in detail.
- SSH keys — how keys reach a machine.
- Errors — the full error catalogue.
Buying more capacity
Not automated yet. Email sales@braesystems.com and we will provision it for you; everything after that is self-serve.