Register Agent
Create a new agent registration and receive an API token.
curl -X POST https://api.rexec.sh/api/agents \
-H "Authorization: Bearer $TOKEN " \
-H "Content-Type: application/json" \
-d '{
"name": "production-server",
"description": "Main production server",
"os": "linux",
"arch": "amd64",
"shell": "/bin/bash",
"tags": ["production", "web"]
}'
Request
POST /api/agents
Optional agent description
Operating system (e.g., “linux”, “darwin”)
Architecture (e.g., “amd64”, “arm64”)
Default shell path (e.g., “/bin/bash”)
Optional tags for organization
Response
API token for WebSocket authentication (save securely - shown only once)
Token name (format: “agent-”)
Token scopes (always [“agent”])
{
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"name" : "production-server" ,
"token" : "rexec_1234567890abcdef" ,
"token_info" : {
"id" : "660e8400-e29b-41d4-a716-446655440001" ,
"name" : "agent-production-server" ,
"scopes" : [ "agent" ],
"note" : "This token is used for agent authentication. Save it securely - it won't be shown again."
}
}
List Agents
Retrieve all agents for the authenticated user.
curl https://api.rexec.sh/api/agents \
-H "Authorization: Bearer $TOKEN "
GET /api/agents
Response
Array of agent objects with online/offline status
[
{
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"name" : "production-server" ,
"description" : "Main production server" ,
"os" : "linux" ,
"arch" : "amd64" ,
"shell" : "/bin/bash" ,
"distro" : "Ubuntu 22.04" ,
"status" : "online" ,
"tags" : [ "production" , "web" ],
"user_id" : "user-123" ,
"created_at" : "2024-01-15T10:30:00Z" ,
"connected_at" : "2024-01-15T14:00:00Z" ,
"last_ping" : "2024-01-15T14:05:30Z" ,
"mfa_locked" : false
}
]
Get Agent
Retrieve a specific agent by ID.
GET /api/agents/:id
Response
Same structure as List Agents, single object.
Update Agent
Update agent name or description.
curl -X PATCH https://api.rexec.sh/api/agents/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TOKEN " \
-H "Content-Type: application/json" \
-d '{
"name": "prod-server-01",
"description": "Updated description"
}'
PATCH /api/agents/:id
Delete Agent
Remove an agent registration. Disconnects if online.
curl -X DELETE https://api.rexec.sh/api/agents/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TOKEN "
DELETE /api/agents/:id
Agent WebSocket Connection
Establish WebSocket connection from agent to server.
GET /api/agents/:id/ws
Authentication
Provide token via one of:
Authorization Header
Subprotocol
Query Parameter
const ws = new WebSocket ( 'wss://api.rexec.sh/api/agents/AGENT_ID/ws' , {
headers: {
'Authorization' : 'Bearer rexec_token'
}
});
Provide system information during connection:
X-Agent-OS: Operating system
X-Agent-Arch: Architecture
X-Agent-Shell: Shell path
X-Agent-Distro: Distribution name
WebSocket Protocol
Messages from Server → Agent
Start a shell session {
"type" : "shell_start" ,
"data" : {
"session_id" : "main" ,
"new_session" : false
}
}
User terminal input {
"type" : "shell_input" ,
"data" : {
"session_id" : "main" ,
"data" : [ 98 , 97 , 115 , 104 ] // byte array
}
}
Terminal resize event {
"type" : "shell_resize" ,
"data" : {
"session_id" : "main" ,
"cols" : 120 ,
"rows" : 30
}
}
Stop specific session {
"type" : "shell_stop_session" ,
"data" : {
"session_id" : "split-abc123"
}
}
Messages from Agent → Server
Terminal output data {
"type" : "shell_output" ,
"data" : {
"session_id" : "main" ,
"data" : [ 72 , 101 , 108 , 108 , 111 ] // byte array
}
}
Shell is starting {
"type" : "shell_starting"
}
Shell successfully started {
"type" : "shell_started"
}
Shell has stopped {
"type" : "shell_stopped"
}
Shell error occurred {
"type" : "shell_error" ,
"data" : "error message"
}
System information update (sent once on connect) {
"type" : "system_info" ,
"data" : {
"hostname" : "prod-server-01" ,
"num_cpu" : 8 ,
"memory" : {
"total" : 16000000000 ,
"available" : 8000000000
},
"disk" : {
"total" : 500000000000 ,
"available" : 250000000000
},
"region" : "us-east-1"
}
}
Real-time resource statistics (sent periodically) {
"type" : "stats" ,
"data" : {
"cpu_usage" : 45.2 ,
"memory_usage" : 8589934592 ,
"memory_limit" : 16000000000 ,
"disk_usage" : 250000000000 ,
"disk_limit" : 500000000000 ,
"network_rx" : 1024000 ,
"network_tx" : 512000
}
}
Heartbeat Protocol
Server sends WebSocket PingMessage every 15 seconds
Agent must respond with PongMessage (WebSocket-level)
Agent can also send JSON {"type": "pong"} message
Connection timeout: 45 seconds without pong
User Terminal Connection
Users connect to agents via WebSocket.
GET /api/agents/:id/terminal
Query Parameters
Client connection ID (stable across reconnects)
If true, creates a new split session
Session Types
Main Session : newSession=false → session ID = "main"
Split Session : newSession=true → session ID = "split-{connection_id}"
User → Agent Messages
Input (JSON)
Input (Binary)
Resize
Execute Command
{
"type" : "input" ,
"data" : "ls -la \n "
}
Agent → User Messages
{
"type" : "output" ,
"data" : "hello world"
}
Get Agent Status
Get real-time agent status and statistics.
GET /api/agents/:id/status
Response
{
"status" : "online" ,
"connected_at" : "2024-01-15T14:00:00Z" ,
"last_ping" : "2024-01-15T14:05:30Z" ,
"sessions" : 2 ,
"os" : "linux" ,
"arch" : "amd64" ,
"system_info" : {
"hostname" : "prod-server-01" ,
"num_cpu" : 8 ,
"memory" : {
"total" : 16000000000 ,
"available" : 8000000000
}
},
"stats" : {
"cpu_usage" : 45.2 ,
"memory_usage" : 8589934592
}
}
Complete Agent Implementation Example
package main
import (
" encoding/json "
" log "
" time "
" github.com/gorilla/websocket "
)
type Message struct {
Type string `json:"type"`
Data json . RawMessage `json:"data"`
}
func main () {
agentID := "550e8400-e29b-41d4-a716-446655440000"
token := "rexec_1234567890abcdef"
header := http . Header {}
header . Set ( "Authorization" , "Bearer " + token )
header . Set ( "X-Agent-OS" , "linux" )
header . Set ( "X-Agent-Arch" , "amd64" )
header . Set ( "X-Agent-Shell" , "/bin/bash" )
url := fmt . Sprintf ( "wss://api.rexec.sh/api/agents/ %s /ws" , agentID )
conn , _ , err := websocket . DefaultDialer . Dial ( url , header )
if err != nil {
log . Fatal ( err )
}
defer conn . Close ()
// Send system info
systemInfo := map [ string ] interface {}{
"hostname" : "prod-server-01" ,
"num_cpu" : 8 ,
"memory" : map [ string ] interface {}{
"total" : 16000000000 ,
"available" : 8000000000 ,
},
}
conn . WriteJSON ( Message {
Type : "system_info" ,
Data : json . RawMessage ( systemInfo ),
})
// Handle messages
for {
var msg Message
if err := conn . ReadJSON ( & msg ); err != nil {
log . Println ( "Read error:" , err )
break
}
switch msg . Type {
case "shell_start" :
// Start PTY and shell process
log . Println ( "Starting shell" )
case "shell_input" :
// Write to PTY stdin
case "shell_resize" :
// Resize PTY
}
}
}