Skip to content

SSH machines ​

Servers the agent may run shell commands on, by name, for the user who saved them — from Chat AI, workflow nodes, the Dedicated Agent and the Teams bot. Saved from the SSH machines tab of the Connections page.

Credentials never come back. password, private_key and passphrase are write-only; the has_* flags say what is stored. They are encrypted at rest and released only to the terminal service, one command at a time, under a short-lived grant Django mints for the turn (30 minutes for a chat turn, an hour for a workflow run). Clients cannot supply a grant themselves: an ssh_grant in a chat or tool payload is stripped.

The host key is pinned on first use. The first successful test records the server's host key. If the server later presents a different key, the machine turns host_key_changed and the agent refuses to use it until you test again with trust_new_host_key: true — do that only when you know the server was rebuilt or its keys rotated.

Commands run without asking. Whatever the agent decides to run runs straight away with the saved login, so save an account with only the access the agent needs. Every command is logged per machine (activity).

Machines are private to their owner — there is no sharing — and each user can save up to 20. A workflow run uses the machines of the workflow's owner, whoever started the run.

Endpoints ​

MethodPathPurpose
GET/ssh-machines/My machines
POST/ssh-machines/Save a machine
GET/ssh-machines/{machine_id}/One machine
PUT/ssh-machines/{machine_id}/Update a machine
DELETE/ssh-machines/{machine_id}/Delete a machine
POST/ssh-machines/{machine_id}/test/Test the connection
GET/ssh-machines/{machine_id}/activity/Recent commands

GET /ssh-machines/ ​

My machines

Auth: Session token · In the app: Connections → SSH machines

Response 200 — Your machines, by name.

Array of:

FieldTypeDescription
idinteger
namestringWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
descriptionstringShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
hoststringHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
portintegerDefault: 22.
usernamestringThe SSH login, e.g. ubuntu.
auth_typestring ("password", "key")Default: "password".
passwordstringFor password login. Blank on update keeps the stored one.
private_keystringFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
passphrasestringThe key's passphrase, if it has one.
has_passwordboolean
has_private_keyboolean
has_passphraseboolean
host_key_fingerprintstringFingerprint of the pinned host key; empty until the first successful test.
statusstring ("untested", "ok", "error", "host_key_changed")untested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
last_ok_atstring (date-time), nullable
last_errorstring
last_used_atstring (date-time), nullableWhen the agent last ran a command on it.
created_atstring (date-time)
updated_atstring (date-time)
userinteger

Example

bash
curl -X GET "https://api.example.com/ssh-machines/" \
  -H "Authorization: Token $FINBLADE_TOKEN"

POST /ssh-machines/ ​

Save a machine

Saves the machine as untested. It is not usable by the agent until a test succeeds, which also pins its host key. The app saves and tests in one step (Save and test).

Auth: Session token · In the app: Connections → SSH machines → Add a machine

Request body (application/json)

FieldTypeRequiredDescription
idintegerno
namestringnoWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
descriptionstringnoShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
hoststringnoHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
portintegernoDefault: 22.
usernamestringnoThe SSH login, e.g. ubuntu.
auth_typestring ("password", "key")noDefault: "password".
passwordstringnoFor password login. Blank on update keeps the stored one.
private_keystringnoFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
passphrasestringnoThe key's passphrase, if it has one.
has_passwordbooleanno
has_private_keybooleanno
has_passphrasebooleanno
host_key_fingerprintstringnoFingerprint of the pinned host key; empty until the first successful test.
statusstring ("untested", "ok", "error", "host_key_changed")nountested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
last_ok_atstring (date-time), nullableno
last_errorstringno
last_used_atstring (date-time), nullablenoWhen the agent last ran a command on it.
created_atstring (date-time)no
updated_atstring (date-time)no
userintegerno
json
{
  "name": "web-1",
  "description": "Production API server, Ubuntu 22.04",
  "host": "10.0.0.5",
  "port": 22,
  "username": "ubuntu",
  "auth_type": "password",
  "password": "correct-horse-battery"
}

Response 201 — Saved.

FieldTypeDescription
idinteger
namestringWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
descriptionstringShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
hoststringHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
portintegerDefault: 22.
usernamestringThe SSH login, e.g. ubuntu.
auth_typestring ("password", "key")Default: "password".
passwordstringFor password login. Blank on update keeps the stored one.
private_keystringFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
passphrasestringThe key's passphrase, if it has one.
has_passwordboolean
has_private_keyboolean
has_passphraseboolean
host_key_fingerprintstringFingerprint of the pinned host key; empty until the first successful test.
statusstring ("untested", "ok", "error", "host_key_changed")untested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
last_ok_atstring (date-time), nullable
last_errorstring
last_used_atstring (date-time), nullableWhen the agent last ran a command on it.
created_atstring (date-time)
updated_atstring (date-time)
userinteger
json
{
  "id": 7,
  "name": "web-1",
  "description": "Production API server, Ubuntu 22.04",
  "host": "10.0.0.5",
  "port": 22,
  "username": "ubuntu",
  "auth_type": "key",
  "has_password": false,
  "has_private_key": true,
  "has_passphrase": false,
  "host_key_fingerprint": "SHA256:4a6f1c0d9e8b7a6c5d4e3f2a1b0c9d8e7f6a5b4c3d2",
  "status": "ok",
  "last_ok_at": "2026-09-24T10:12:40Z",
  "last_error": "",
  "last_used_at": "2026-09-25T07:03:11Z",
  "created_at": "2026-09-23T14:02:09Z",
  "updated_at": "2026-09-24T10:12:40Z",
  "user": 42
}

Response 400 — Validation error, or you already have 20 machines.

json
{
  "name": [
    "You already have a machine called \"web-1\"."
  ]
}

Errors

StatusBodyWhen
400{"detail":"You can save at most 20 machines."}The per-user limit is reached.
400{"password":["A password is required."]}auth_type is password and no password is stored or sent.
400{"private_key":["Paste the PRIVATE key (it starts with \"-----BEGIN ... PRIVATE KEY-----\")."]}A public key, certificate or other text was sent as the key.
400{"username":["Enter the SSH login name (e.g. \"ubuntu\")."]}The login contains characters an SSH user name cannot.

Example

bash
curl -X POST "https://api.example.com/ssh-machines/" \
  -H "Authorization: Token $FINBLADE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"web-1","description":"Production API server, Ubuntu 22.04","host":"10.0.0.5","port":22,"username":"ubuntu","auth_type":"password","password":"correct-horse-battery"}'

GET /ssh-machines/{machine_id}/ ​

One machine

Auth: Session token

Response 200 — The machine.

FieldTypeDescription
idinteger
namestringWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
descriptionstringShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
hoststringHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
portintegerDefault: 22.
usernamestringThe SSH login, e.g. ubuntu.
auth_typestring ("password", "key")Default: "password".
passwordstringFor password login. Blank on update keeps the stored one.
private_keystringFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
passphrasestringThe key's passphrase, if it has one.
has_passwordboolean
has_private_keyboolean
has_passphraseboolean
host_key_fingerprintstringFingerprint of the pinned host key; empty until the first successful test.
statusstring ("untested", "ok", "error", "host_key_changed")untested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
last_ok_atstring (date-time), nullable
last_errorstring
last_used_atstring (date-time), nullableWhen the agent last ran a command on it.
created_atstring (date-time)
updated_atstring (date-time)
userinteger
json
{
  "id": 7,
  "name": "web-1",
  "description": "Production API server, Ubuntu 22.04",
  "host": "10.0.0.5",
  "port": 22,
  "username": "ubuntu",
  "auth_type": "key",
  "has_password": false,
  "has_private_key": true,
  "has_passphrase": false,
  "host_key_fingerprint": "SHA256:4a6f1c0d9e8b7a6c5d4e3f2a1b0c9d8e7f6a5b4c3d2",
  "status": "ok",
  "last_ok_at": "2026-09-24T10:12:40Z",
  "last_error": "",
  "last_used_at": "2026-09-25T07:03:11Z",
  "created_at": "2026-09-23T14:02:09Z",
  "updated_at": "2026-09-24T10:12:40Z",
  "user": 42
}

Response 404 — Not one of your machines.

Example

bash
curl -X GET "https://api.example.com/ssh-machines/{machine_id}/" \
  -H "Authorization: Token $FINBLADE_TOKEN"

PUT /ssh-machines/{machine_id}/ ​

Update a machine

Partial update — send only what changes. A credential left blank or omitted keeps the stored one; switching auth_type discards the other kind of credential.

Changing the login (username, auth_type or a credential) or the address (host, port) sets the machine back to untested. Changing the address also forgets the pinned host key: a different host is a different server.

Auth: Session token · In the app: Connections → SSH machines → Edit

Request body (application/json)

FieldTypeRequiredDescription
idintegerno
namestringnoWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
descriptionstringnoShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
hoststringnoHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
portintegernoDefault: 22.
usernamestringnoThe SSH login, e.g. ubuntu.
auth_typestring ("password", "key")noDefault: "password".
passwordstringnoFor password login. Blank on update keeps the stored one.
private_keystringnoFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
passphrasestringnoThe key's passphrase, if it has one.
has_passwordbooleanno
has_private_keybooleanno
has_passphrasebooleanno
host_key_fingerprintstringnoFingerprint of the pinned host key; empty until the first successful test.
statusstring ("untested", "ok", "error", "host_key_changed")nountested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
last_ok_atstring (date-time), nullableno
last_errorstringno
last_used_atstring (date-time), nullablenoWhen the agent last ran a command on it.
created_atstring (date-time)no
updated_atstring (date-time)no
userintegerno
json
{
  "description": "Production API server (Ubuntu 24.04)"
}

Response 200 — Updated.

FieldTypeDescription
idinteger
namestringWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
descriptionstringShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
hoststringHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
portintegerDefault: 22.
usernamestringThe SSH login, e.g. ubuntu.
auth_typestring ("password", "key")Default: "password".
passwordstringFor password login. Blank on update keeps the stored one.
private_keystringFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
passphrasestringThe key's passphrase, if it has one.
has_passwordboolean
has_private_keyboolean
has_passphraseboolean
host_key_fingerprintstringFingerprint of the pinned host key; empty until the first successful test.
statusstring ("untested", "ok", "error", "host_key_changed")untested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
last_ok_atstring (date-time), nullable
last_errorstring
last_used_atstring (date-time), nullableWhen the agent last ran a command on it.
created_atstring (date-time)
updated_atstring (date-time)
userinteger
json
{
  "id": 7,
  "name": "web-1",
  "description": "Production API server, Ubuntu 22.04",
  "host": "10.0.0.5",
  "port": 22,
  "username": "ubuntu",
  "auth_type": "key",
  "has_password": false,
  "has_private_key": true,
  "has_passphrase": false,
  "host_key_fingerprint": "SHA256:4a6f1c0d9e8b7a6c5d4e3f2a1b0c9d8e7f6a5b4c3d2",
  "status": "ok",
  "last_ok_at": "2026-09-24T10:12:40Z",
  "last_error": "",
  "last_used_at": "2026-09-25T07:03:11Z",
  "created_at": "2026-09-23T14:02:09Z",
  "updated_at": "2026-09-24T10:12:40Z",
  "user": 42
}

Response 400 — Validation error.

json
{
  "username": [
    "A user with that username already exists."
  ]
}

Response 404 — Not one of your machines.

Example

bash
curl -X PUT "https://api.example.com/ssh-machines/{machine_id}/" \
  -H "Authorization: Token $FINBLADE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"description":"Production API server (Ubuntu 24.04)"}'

DELETE /ssh-machines/{machine_id}/ ​

Delete a machine

The agent can no longer use it. Its command history is kept.

Auth: Session token · In the app: Connections → SSH machines → Delete

Response 200 — Deleted.

FieldTypeDescription
messagestring
json
{
  "message": "Success"
}

Response 404 — Not one of your machines.

Example

bash
curl -X DELETE "https://api.example.com/ssh-machines/{machine_id}/" \
  -H "Authorization: Token $FINBLADE_TOKEN"

POST /ssh-machines/{machine_id}/test/ ​

Test the connection

Connects through the terminal service, runs a harmless command and records the outcome on the machine (status, last_ok_at, last_error). The first success pins the server's host key.

Always answers 200 with ok — an unreachable server is a result, not an API error. error_type: host_key_changed means the server presented a different key from the pinned one; test again with trust_new_host_key: true only if you know why it changed. Allow up to 45 seconds.

Auth: Session token · In the app: Connections → SSH machines → Test / Trust new key

Path parameters

FieldTypeRequiredDescription
machine_idintegeryes

Request body (application/json)

FieldTypeRequiredDescription
trust_new_host_keybooleannoReplace the pinned host key with the one the server presents now. Default: false.
json
{
  "trust_new_host_key": false
}

Response 200 — The outcome, and the machine as updated.

FieldTypeDescription
okboolean
errorstring, nullable
error_typestring, nullableThe terminal service's reason code, when it gives one. host_key_changed is the one that needs a decision from you.
fingerprintstring, nullableThe host key the server presented.
outputstringWhat the test command printed (first 500 characters).
latency_msinteger, nullable
machineobjectA saved server. Credentials are write-only; the has_* flags report what is stored.
machine.idinteger
machine.namestringWhat the agent calls it. 1–64 letters, digits, ., - or _, starting with a letter or digit; unique per user (case-insensitive).
machine.descriptionstringShown to the agent to help it pick the right machine, e.g. Production API server, Ubuntu 22.04.
machine.hoststringHostname or IP. Addresses the platform refuses to reach (internal networks, metadata endpoints) are rejected.
machine.portintegerDefault: 22.
machine.usernamestringThe SSH login, e.g. ubuntu.
machine.auth_typestring ("password", "key")Default: "password".
machine.passwordstringFor password login. Blank on update keeps the stored one.
machine.private_keystringFor key login: the whole PEM / OpenSSH private key, including the BEGIN and END lines (max 16 KB). PuTTY .ppk keys are not accepted. Blank on update keeps the stored one.
machine.passphrasestringThe key's passphrase, if it has one.
machine.has_passwordboolean
machine.has_private_keyboolean
machine.has_passphraseboolean
machine.host_key_fingerprintstringFingerprint of the pinned host key; empty until the first successful test.
machine.statusstring ("untested", "ok", "error", "host_key_changed")untested after saving or changing the login or address. A machine is usable once a test has succeeded (its host key is pinned) and stays usable until its host key changes; a later test that merely fails to connect does not lock it out.
machine.last_ok_atstring (date-time), nullable
machine.last_errorstring
machine.last_used_atstring (date-time), nullableWhen the agent last ran a command on it.
machine.created_atstring (date-time)
machine.updated_atstring (date-time)
machine.userinteger
json
{
  "ok": true,
  "error": null,
  "error_type": null,
  "fingerprint": "SHA256:4a6f1c0d9e8b7a6c5d4e3f2a1b0c9d8e7f6a5b4c3d2",
  "output": "Linux web-1 6.8.0-45-generic x86_64",
  "latency_ms": 612,
  "machine": {
    "id": 7,
    "name": "web-1",
    "status": "ok"
  }
}

Response 404 — Not one of your machines.

Example

bash
curl -X POST "https://api.example.com/ssh-machines/<machine_id>/test/" \
  -H "Authorization: Token $FINBLADE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"trust_new_host_key":false}'

GET /ssh-machines/{machine_id}/activity/ ​

Recent commands

The last 50 commands run on this machine, newest first.

Auth: Session token · In the app: Connections → SSH machines → Recent commands

Path parameters

FieldTypeRequiredDescription
machine_idintegeryes

Response 200 — Commands.

Array of:

FieldTypeDescription
idinteger
machine_namestring
commandstringThe command as run (truncated to 4,000 characters).
sourcestring ("chat", "teams", "workflow", "dedicated", "test")Where the command came from.
conversation_idstring, nullableThe chat conversation, for chat, teams and dedicated.
workflow_idstring, nullableThe workflow, for workflow.
exit_codeinteger, nullablenull while the command is still running.
duration_msinteger, nullable
errorstring
created_atstring (date-time)
finished_atstring (date-time), nullable

Response 404 — Not one of your machines.

Example

bash
curl -X GET "https://api.example.com/ssh-machines/<machine_id>/activity/" \
  -H "Authorization: Token $FINBLADE_TOKEN"

Finblade documentation