Skip to Content
Quickstart

Quickstart

1. Get an API key

API keys are created in the dashboard, not through the API.

  1. Sign in to the dashboard — enter your email and we send you a six-digit code. There is no password.
  2. Go to API keys and click Generate new key.
  3. 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_ID and 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/docs

That 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

Buying more capacity

Not automated yet. Email sales@braesystems.com and we will provision it for you; everything after that is self-serve.

Last updated on