A server contains a tunnel, carrier, accepted method combinations, and the settings needed to connect. Start with the direct SSH example, then use connection examples for other tunnels.
All endpoints require the owning account's Client API key. Set the quickstart variables before running shell examples.
List servers
GET /api/v1/configs/{config_key}/servers
Returns a servers array plus configuration identifiers. Entries contain id, unique_key, name, category, tunnel, carrier, accepted_methods, internal, created_at, and updated_at. This is a summary: credentials and full connection settings are omitted.
Create a server
POST /api/v1/configs/{config_key}/servers
Save this as server.json and replace the example connection details:
{
"name": "My SSH server",
"tunnel": {
"family": "ssh",
"variant": "default"
},
"carrier": {
"type": "default",
"settings": {}
},
"accepted_methods": [
[]
],
"settings": {
"endpoint": {
"hosts": [
"ssh.example.com"
],
"ports": [
22
]
},
"credentials": {
"username": "demo",
"password": "replace-me"
}
}
}
curl --fail-with-body --request POST "$API_BASE/configs/$CONFIG_KEY/servers" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header "X-API-Key: $CLIENT_API_KEY" \
--data-binary @server.json
| Field | Type | On creation |
|---|---|---|
name |
string | Required; up to 100 characters |
tunnel |
object | Required; family and variant identify the protocol |
carrier |
object | Required; type and settings identify the transport carrier |
accepted_methods |
array of arrays | Required; [[]] allows direct connections only |
settings |
object | Required; protocol-specific endpoint, credentials, or profile |
category |
string or null | Optional; up to 100 characters; participates in app matching |
note |
string or null | Optional; up to 255 characters |
unique_key |
string | Only in batch sync; individual creation assigns a key and individual edits use the URL |
gaming, torrent, show_banner |
boolean | Optional Client API presentation flags |
The server count limit applies per configuration, using the owning account's allowance. Successful creation returns HTTP 201 Created, a Location header pointing to the new resource, and the full editable object in server, beside success and message. The response includes private settings and uses Cache-Control: no-store, private.
Read a server for editing
GET /api/v1/configs/{config_key}/servers/{server_key}
export SERVER_KEY='PASTE_THE_RETURNED_SERVER_UNIQUE_KEY'
curl --fail-with-body "$API_BASE/configs/$CONFIG_KEY/servers/$SERVER_KEY" \
--header 'Accept: application/json' \
--header "X-API-Key: $CLIENT_API_KEY"
Returns the full editable object in server, including settings, carrier settings, and credentials. The response uses Cache-Control: no-store, private. Owner API key required. Internal servers cannot be read for editing and return 403.
For a read/edit/write workflow, copy only writable fields from server: name, category, note, tunnel, carrier, accepted_methods, and settings. Do not send response-only id or internal fields back. The URL supplies the resource key. The detail response also includes writable gaming, torrent, and show_banner flags.
Update a server
PATCH /api/v1/configs/{config_key}/servers/{server_key}
Rename a server without resending credentials:
curl --fail-with-body --request PATCH "$API_BASE/configs/$CONFIG_KEY/servers/$SERVER_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header "X-API-Key: $CLIENT_API_KEY" \
--data '{"name":"Primary SSH"}'
Metadata-only edits preserve the connection. To update credentials, send a complete credentials object, including both values you want to keep:
{
"settings": {
"credentials": {"username": "demo", "password": "new-password"}
}
}
Settings merge at the first level: a supplied credentials or endpoint object replaces that entire object. Supplying tunnel replaces the connection and requires a complete valid connection document. Send a whole carrier object or accepted_methods array when changing those values.
PATCH changes an existing server and returns the full editable object in server. A missing key returns 404 and never creates a server. Use batch sync when you intentionally need upsert.
Replace a server
PUT /api/v1/configs/{config_key}/servers/{server_key}
Use PUT only for a complete replacement of an existing server. Include name, tunnel, carrier, accepted_methods, and settings. Omitted optional fields reset to their defaults: category and note become null; presentation flags become false. The existing identity is preserved. Missing required groups return 422; a missing resource returns 404.
Use the same complete JSON shape as creation, without response-only id, internal, or unique_key fields. PUT returns HTTP 200 and the editable object in server. Use PATCH for a rename, credential rotation, or another partial change.
Delete a server
DELETE /api/v1/configs/{config_key}/servers/{server_key}
curl --fail-with-body --request DELETE "$API_BASE/configs/$CONFIG_KEY/servers/$SERVER_KEY" \
--header 'Accept: application/json' \
--header "X-API-Key: $CLIENT_API_KEY"
Returns success: true and server containing unique_key and action: "deleted". A missing resource returns 404. This removes the server from the configuration.
Protected resources
Resources marked internal: true are protected even when they belong to your configuration. Lists expose only id, unique_key, name, category, internal, and timestamps. Connection groups, credentials, profiles, method values, and notes are omitted.
Only removal is allowed. Detail reads and PATCH/PUT edits return 403; batch sync also rejects any attempt to update a protected key, including a request that removes and recreates that same key. Delete it through the individual DELETE endpoint or the batch removal array. Neither Client nor Business requests can set the internal flag or turn protected resources into editable resources.