Skip to main content

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
name
string
required
Agent display name
description
string
Optional agent description
os
string
Operating system (e.g., “linux”, “darwin”)
arch
string
Architecture (e.g., “amd64”, “arm64”)
shell
string
Default shell path (e.g., “/bin/bash”)
tags
string[]
Optional tags for organization

Response

id
string
Agent UUID
name
string
Agent name
token
string
API token for WebSocket authentication (save securely - shown only once)
token_info
object
Response Example
{
  "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

agents
array
Array of agent objects with online/offline status
Response Example
[
  {
    "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
id
string
required
Agent UUID

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
name
string
New agent name
description
string
New description

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:
const ws = new WebSocket('wss://api.rexec.sh/api/agents/AGENT_ID/ws', {
  headers: {
    'Authorization': 'Bearer rexec_token'
  }
});

Agent Headers (Optional)

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

shell_start
object
Start a shell session
{
  "type": "shell_start",
  "data": {
    "session_id": "main",
    "new_session": false
  }
}
shell_input
object
User terminal input
{
  "type": "shell_input",
  "data": {
    "session_id": "main",
    "data": [98, 97, 115, 104]  // byte array
  }
}
shell_resize
object
Terminal resize event
{
  "type": "shell_resize",
  "data": {
    "session_id": "main",
    "cols": 120,
    "rows": 30
  }
}
shell_stop
object
Stop all shell sessions
{
  "type": "shell_stop"
}
shell_stop_session
object
Stop specific session
{
  "type": "shell_stop_session",
  "data": {
    "session_id": "split-abc123"
  }
}

Messages from Agent → Server

shell_output
object
Terminal output data
{
  "type": "shell_output",
  "data": {
    "session_id": "main",
    "data": [72, 101, 108, 108, 111]  // byte array
  }
}
shell_starting
object
Shell is starting
{
  "type": "shell_starting"
}
shell_started
object
Shell successfully started
{
  "type": "shell_started"
}
shell_stopped
object
Shell has stopped
{
  "type": "shell_stopped"
}
shell_error
object
Shell error occurred
{
  "type": "shell_error",
  "data": "error message"
}
system_info
object
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"
  }
}
stats
object
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
  }
}
pong
object
Heartbeat response
{
  "type": "pong"
}

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

id
string
Client connection ID (stable across reconnects)
newSession
boolean
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

{
  "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

Online Agent
{
  "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
  }
}
Offline Agent
{
  "status": "offline"
}

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
        }
    }
}

Build docs developers (and LLMs) love