Persistent SSH sessions for LLMs. Works standalone or via Synapse gateway.
Do NOT guess or invent endpoint paths. Only the paths listed on this page exist.
Both /X and /ssh/X work (e.g. /targets and /ssh/targets).
If you get a 404, call GET /endpoints for a machine-readable list of ALL valid endpoints.
Add ?key=YOUR_KEY to ANY URL for auth. All parameter-bearing endpoints accept GET with query params:
open https://ssh.proxy.schaefer.zone/sessions?key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/SESSION_ID/output?key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/SESSION_ID/close?key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/connect?target=vps1&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/SESSION_ID/exec?command=hostname&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/SESSION_ID/sftp/ls?path=/&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/SESSION_ID/sftp/download?path=/etc/hosts&encoding=text&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/SESSION_ID/sftp/upload?path=/tmp/test.txt&content=hello&encoding=text&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/new?host=vps1.schaefer.zone&port=22&username=root&privateKey=...&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/targets/create?name=vps1&host=...&username=root&privateKey=...&key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/targets/vps1/delete?key=YOUR_KEY
open https://ssh.proxy.schaefer.zone/endpoints
Note: For /targets registration, POST with JSON body is cleaner (large privateKey). Use GET /targets/create only when POST is unavailable.
| Method | Path | open-tool URL | Description |
|---|---|---|---|
| GET | /health | β (no auth) | Health check (Docker) |
| GET | /endpoints | β (no auth) | Machine-readable endpoint list |
| GET | /help | β (no auth) | Full API documentation |
| POST | /targets | β (needs JSON body) | Register SSH target (name, host, port?, username, privateKey) |
| GET | /targets/create | /targets/create?name=vps1&host=...&port=22&username=root&privateKey=...&key=... | Register target via GET (port defaults to 22) |
| GET | /targets | /targets?key=... | List targets (no keys!) |
| GET | /targets/:name | /targets/vps1?key=... | Get one target |
| DELETE | /targets/:name | β | Delete target |
| GET | /targets/:name/delete | /targets/vps1/delete?key=... | Delete target via GET (open-tool OK) |
| POST | /connect | β (needs JSON body) | Connect by target name |
| GET | /connect | /connect?target=vps1&key=... | GET alternative for /connect |
| POST | /new | β (needs JSON body) | Create session (host, port?, username, privateKey/password) |
| GET | /new | /new?host=...&port=22&username=root&privateKey=...&key=... | Create session via GET (port defaults to 22) |
| POST | /:id/exec | β (needs JSON body) | Execute command |
| GET | /:id/exec | /:id/exec?command=ls&key=... | Execute command via GET |
| GET | /:id/exec/:execId | /:id/exec/:execId?key=... | Poll exec result |
| GET | /:id/output | /:id/output?key=... | Get session output |
| GET | /sessions | /sessions?key=... | List active sessions |
| DELETE | /:id | β | Close session |
| GET | /:id/close | /:id/close?key=... | Close session via GET |
| Method | Path | open-tool URL | Description |
|---|---|---|---|
| POST | /:id/sftp/download | β (needs JSON body) | Download single file (JSON: {path, encoding?}) |
| GET | /:id/sftp/download | /:id/sftp/download?path=/etc/hosts&encoding=text&key=... | Download file via GET |
| POST | /:id/sftp/download/batch | β (needs JSON body) | Download multiple files (JSON: {paths, encoding?}) |
| POST | /:id/sftp/upload | β (needs JSON body) | Upload single file (JSON: {path, content, encoding?}) |
| GET | /:id/sftp/upload | /:id/sftp/upload?path=/tmp/test.txt&content=hello&encoding=text&key=... | Upload file via GET |
| POST | /:id/sftp/upload/batch | β (needs JSON body) | Upload multiple files (JSON: {files: [{path, content}]}) |
| GET | /:id/sftp/ls | /:id/sftp/ls?path=/&key=... | List directory contents |
| GET | /:id/sftp/stat | /:id/sftp/stat?path=/etc/hosts&key=... | File metadata (size, permissions, etc.) |
| POST | /:id/sftp/mkdir | β (needs JSON body) | Create directory (JSON: {path}) |
| GET | /:id/sftp/mkdir | /:id/sftp/mkdir?path=/tmp/newdir&key=... | Create directory via GET |
| POST | /:id/sftp/rm | β (needs JSON body) | Delete file (JSON: {path}) |
| GET | /:id/sftp/rm | /:id/sftp/rm?path=/tmp/old.txt&key=... | Delete file via GET |
| POST | /:id/sftp/rename | β (needs JSON body) | Rename/move file (JSON: {oldPath, newPath}) |
SFTP encoding: base64 (default) β for binary files, images, etc. text β for text/UTF-8 files (configs, scripts, logs).
SFTP limits: Max 50MB per file. Max 20 files per batch request. Parent dirs are auto-created on upload.
All paths also work with /ssh/ prefix (e.g. /ssh/targets) for backward compatibility with the Synapse gateway.
Every endpoint supports both POST (JSON body) and GET (query params). Use POST with curl, use GET with DeepSeek's open tool.
Every request (except /health, /endpoints, /help, /) requires auth:
Authorization: Bearer YOUR_KEY?key=YOUR_KEY (fallback for open-tool-only LLMs, rate-limited 60/min)Accepted keys:
SSH_PROXY_API_KEY env var) β works without SynapsePOST /targets with {name, host, username, privateKey} β register target (one-time)POST /connect {"target":"vps1"} β get session_idPOST /SESSION_ID/exec {"command":"..."} β start command, get exec_idGET /SESSION_ID/exec/EXEC_ID β poll for resultsDELETE /SESSION_ID or GET /SESSION_ID/close β cleanup?key= works on ALL endpoints β even the existing GET ones./targets + /connect over /new β no privateKey in every request.π§ SSH Proxy API v1.5.0 Β· Built by Super Z (Z.ai) for Michael SchΓ€fer Β· 2026