Skip to main content

Overview

Enigma provides two ways to receive responses:
MethodHow It WorksBest For
RESTResults returned inline if task completes within 50s, otherwise pollStateless, serverless, simple integrations
WebSocketReal-time events pushed as they occurReal-time UIs, live monitoring

REST API Response Formats

Inline Results (< 50 seconds)

Both /run-task and /send-message wait up to 50 seconds for task completion. If the task finishes in time, you get the result immediately. Structure:
{
  "success": true,
  "sessionId": "a1b2c3d4e5f6",
  "taskId": "x9y8z7w6v5u4",
  "status": "complete",
  "result": {
    "type": "task_completed",
    "data": {
      "message": "Successfully completed the search",
      "prompt_tokens": 12450,
      "completion_tokens": 3200,
      "total_tokens": 15650,
      "completion_time": 23.5
    }
  }
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
sessionIdstringSession identifier
taskIdstringTask identifier
statusstringTask status: "complete"
resultobjectTask result details
result.typestringResult type: "task_completed"
result.dataobjectResult data
result.data.messagestringTask completion message
result.data.prompt_tokensnumberInput tokens used
result.data.completion_tokensnumberOutput tokens generated
result.data.total_tokensnumberTotal tokens used
result.data.completion_timenumberExecution time in seconds

Pending Results (> 50 seconds)

For longer tasks, the response returns immediately with a poll URL. Structure:
{
  "success": true,
  "sessionId": "a1b2c3d4e5f6",
  "taskId": "x9y8z7w6v5u4",
  "status": "pending",
  "pending": true,
  "pollUrl": "https://connect.enigma.click/task/a1b2c3d4e5f6/x9y8z7w6v5u4",
  "message": "Task still running. Poll GET /task/:sessionId/:taskId for result."
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
sessionIdstringSession identifier
taskIdstringTask identifier for polling
statusstringTask status: "pending"
pendingbooleantrue when task is still running
pollUrlstringURL to poll for task result
messagestringInstruction to poll for result

Polling Responses

Poll GET /task/:sessionId/:taskId until pending: false or a final type is returned.

Still Running

{
  "success": true,
  "status": "active",
  "pending": true,
  "usage": {
    "inputTokens": 8000,
    "outputTokens": 2100,
    "computeTime": 3,
    "cost": 0.0067
  }
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
statusstring"active" - task is running
pendingbooleantrue - continue polling
usageobjectCurrent usage statistics

Task Completed

{
  "success": true,
  "type": "task_completed",
  "data": {
    "message": "Task finished successfully",
    "prompt_tokens": 12450,
    "completion_tokens": 3200,
    "total_tokens": 15650,
    "completion_time": 23.5
  },
  "usage": {
    "inputTokens": 12450,
    "outputTokens": 3200,
    "computeTime": 5,
    "cost": 0.0124
  },
  "completedAt": "2024-01-15T10:30:00Z"
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
typestring"task_completed"
dataobjectTask result data
data.messagestringCompletion message
data.prompt_tokensnumberTotal input tokens
data.completion_tokensnumberTotal output tokens
data.total_tokensnumberTotal tokens
data.completion_timenumberExecution time in seconds
usageobjectFinal usage statistics
completedAtstringISO 8601 completion timestamp

Guardrail Triggered

{
  "success": true,
  "type": "guardrail_trigger",
  "data": {
    "type": "human_input_needed",
    "value": "I need login credentials to proceed"
  }
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
typestring"guardrail_trigger"
dataobjectGuardrail details
data.typestringGuardrail type
data.valuestringMessage explaining what’s needed
Next Steps: Respond with guardrail message via POST /start/send-message:
{
  "sessionId": "a1b2c3d4e5f6",
  "message": {
    "actionType": "guardrail",
    "taskDetails": "Username: user@example.com, Password: pass123",
    "newState": "resume"
  }
}

Task Failed

{
  "success": false,
  "status": "failed",
  "error": "Navigation timeout after 30 seconds",
  "code": "NAVIGATION_TIMEOUT",
  "usage": {
    "inputTokens": 5000,
    "outputTokens": 1200,
    "computeTime": 2,
    "cost": 0.0045
  }
}
Response Fields:
FieldTypeDescription
successbooleanfalse
statusstring"failed"
errorstringError message
codestringError code
usageobjectUsage statistics up to failure

Session Creation Response

POST /start/start-session returns session details and streaming configuration.
{
  "success": true,
  "sessionId": "a1b2c3d4e5f6",
  "socketURL": "https://connect.enigma.click",
  "streaming": {
    "webRTCURL": "https://74.235.190.31:8889/a1b2c3d4e5f6/whep",
    "webViewURL": "https://74.235.190.31:8889/a1b2c3d4e5f6",
    "dimensions": {
      "width": 1024,
      "height": 600
    }
  },
  "initialPrompt": "Go to amazon.com",
  "expiresIn": 300000,
  "balance": 12.50,
  "message": "Connect to instance using sessionId in auth"
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
sessionIdstringUnique session identifier
socketURLstringWebSocket connection URL
streamingobjectVideo streaming configuration
streaming.webRTCURLstringWebRTC WHEP endpoint
streaming.webViewURLstringHTTP video stream URL
streaming.dimensionsobjectVideo dimensions
initialPromptstringInitial task provided
expiresInnumberSession expiration time (ms)
balancenumberCurrent account balance (USD)
messagestringAdditional information

State Control Response

POST /start/send-message with actionType: "state", "interaction", or "guardrail" returns immediate confirmation.
{
  "success": true,
  "message": "Message sent successfully"
}
Response Fields:
FieldTypeDescription
successbooleanRequest success indicator
messagestringConfirmation message

WebSocket Event Formats

Connect via Socket.IO and listen for message events:
socket.on("message", (data) => {
  console.log(data.type, data);
});

Event: agent

Live agent thoughts and reasoning during task execution.
{
  "type": "agent",
  "content": "I'll navigate to the search box and enter the query..."
}
Fields:
FieldTypeDescription
typestring"agent"
contentstringAgent reasoning text

Event: action

Browser action performed by the agent.
{
  "type": "action",
  "data": {
    "name": "click_element"
  }
}
Fields:
FieldTypeDescription
typestring"action"
dataobjectAction details
data.namestringAction name

Event: response_update

Status update during task execution.
{
  "type": "response_update",
  "data": {
    "message": "Starting task... Browsing the web now."
  }
}
Fields:
FieldTypeDescription
typestring"response_update"
dataobjectUpdate details
data.messagestringStatus message

Event: task_completed

Task finished successfully.
{
  "type": "task_completed",
  "taskId": "x9y8z7w6v5u4",
  "data": {
    "message": "Task completed successfully",
    "prompt_tokens": 15420,
    "completion_tokens": 8230,
    "total_tokens": 23650,
    "completion_time": 45.3,
    "usage": {
      "cost": 0.0234
    }
  }
}
Fields:
FieldTypeDescription
typestring"task_completed"
taskIdstringTask identifier
dataobjectCompletion details
data.messagestringCompletion message
data.prompt_tokensnumberInput tokens used
data.completion_tokensnumberOutput tokens generated
data.total_tokensnumberTotal tokens used
data.completion_timenumberExecution time (seconds)
data.usageobjectUsage statistics
data.usage.costnumberCost in USD

Event: guardrail_trigger

Agent needs human input to continue.
{
  "type": "guardrail_trigger",
  "data": {
    "type": "human_input_needed",
    "value": "I need login credentials to proceed"
  }
}
Fields:
FieldTypeDescription
typestring"guardrail_trigger"
dataobjectGuardrail details
data.typestringGuardrail type
data.valuestringMessage explaining what’s needed
Respond with:
socket.emit("message", {
  actionType: "guardrail",
  taskDetails: "Username: demo@example.com, Password: demo123",
  newState: "resume"
});

Event: error

Task failed with error.
{
  "type": "error",
  "error": "Navigation timeout after 30 seconds",
  "code": "NAVIGATION_TIMEOUT"
}
Fields:
FieldTypeDescription
typestring"error"
errorstringError message
codestringError code

Connection Events

connect

Socket connected successfully.
socket.on("connect", () => {
  console.log("Connected to session");
});

disconnect

Socket disconnected.
socket.on("disconnect", () => {
  console.log("Disconnected from session");
});

error

Socket error occurred.
socket.on("error", (err) => {
  console.error("Socket error:", err);
});

end_session

Session terminated by server.
{
  "reason": "completed"
}
Possible Reasons:
  • "completed" - Task completed
  • "terminated" - Manually terminated
  • "expired" - Session timeout
  • "terminateOnCompletion" - Auto-terminated after task
  • "instance_lost" - Instance connection lost
socket.on("end_session", (data) => {
  console.log("Session ended:", data.reason);
});

instance:disconnected

Instance connection lost. Session enters 5-minute grace period for reconnection.
{
  "gracePeriod": 300000
}
socket.on("instance:disconnected", (data) => {
  console.log("Instance lost, waiting for reconnection...");
  console.log("Grace period:", data.gracePeriod, "ms");
});

instance:reconnected

Instance connection recovered.
socket.on("instance:reconnected", (data) => {
  console.log("Instance reconnected");
});

OpenAI-Compatible Response Formats

Non-Streaming Response

POST /v1/chat/completions with stream: false (default).
{
  "id": "chatcmpl-a1b2c3d4e5f6",
  "object": "chat.completion",
  "created": 1704067200,
  "model": "enigma-browser-1",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "I found 5 headings on example.com:\n1. Example Domain\n2. More Information\n3. Contact\n4. About\n5. Privacy Policy"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 8450,
    "completion_tokens": 2100,
    "total_tokens": 10550
  },
  "enigma": {
    "sessionId": "a1b2c3d4e5f6",
    "taskId": "x9y8z7w6v5u4",
    "cost": 0.0089
  }
}
Response Fields:
FieldTypeDescription
idstringCompletion identifier
objectstring"chat.completion"
creatednumberUnix timestamp
modelstringModel name: "enigma-browser-1"
choicesarrayArray of completion choices
choices[0].indexnumberChoice index (always 0)
choices[0].messageobjectAssistant message
choices[0].message.rolestring"assistant"
choices[0].message.contentstringResponse text
choices[0].finish_reasonstring"stop"
usageobjectToken usage statistics
usage.prompt_tokensnumberInput tokens
usage.completion_tokensnumberOutput tokens
usage.total_tokensnumberTotal tokens
enigmaobjectEnigma-specific metadata
enigma.sessionIdstringSession identifier
enigma.taskIdstringTask identifier
enigma.costnumberCost in USD

Streaming Response (SSE)

POST /v1/chat/completions with stream: true returns Server-Sent Events. Stream Format:
data: {"id":"chatcmpl-a1b2c3","object":"chat.completion.chunk","created":1704067200,"model":"enigma-browser-1","choices":[{"index":0,"delta":{"role":"assistant","content":"I"},"finish_reason":null}]}

data: {"id":"chatcmpl-a1b2c3","object":"chat.completion.chunk","created":1704067200,"model":"enigma-browser-1","choices":[{"index":0,"delta":{"content":" found"},"finish_reason":null}]}

data: {"id":"chatcmpl-a1b2c3","object":"chat.completion.chunk","created":1704067200,"model":"enigma-browser-1","choices":[{"index":0,"delta":{"content":" 5"},"finish_reason":null}]}

data: {"id":"chatcmpl-a1b2c3","object":"chat.completion.chunk","created":1704067200,"model":"enigma-browser-1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
Chunk Structure:
FieldTypeDescription
idstringCompletion identifier
objectstring"chat.completion.chunk"
creatednumberUnix timestamp
modelstring"enigma-browser-1"
choicesarrayArray of delta choices
choices[0].indexnumberChoice index (always 0)
choices[0].deltaobjectContent delta
choices[0].delta.rolestring"assistant" (first chunk only)
choices[0].delta.contentstringText chunk
choices[0].finish_reasonstringnull during stream, "stop" at end
Handling Streams:
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://connect.enigma.click/v1',
  apiKey: 'YOUR_API_KEY'
});

const stream = await client.chat.completions.create({
  model: 'enigma-browser-1',
  messages: [{ role: 'user', content: 'Go to example.com' }],
  stream: true
});

for await (const chunk of stream) {
  const content = chunk.choices[0]?.delta?.content || '';
  process.stdout.write(content);
}

Error Response Format

All errors follow this standard format:
{
  "success": false,
  "message": "Human-readable error message"
}
Common HTTP Status Codes:
StatusMeaningExample Message
200Success-
400Bad request"sessionId and message are required"
401Unauthorized"Invalid or revoked API key"
402Payment required"Insufficient balance."
403Forbidden"Account is deactivated"
404Not found"Session not found"
429Too many requests"Rate limit exceeded. Please try again later."
500Internal server error"Internal server error"
503Service unavailable"No available instances."
See Rate Limits for handling 429 errors.

Usage Object Structure

The usage object appears in many responses and provides token and cost information:
interface Usage {
  inputTokens: number;      // Number of input tokens used
  outputTokens: number;     // Number of output tokens generated
  computeTime: number;      // Compute time in seconds
  cost: number;             // Cost in USD
}
Example:
{
  "usage": {
    "inputTokens": 12450,
    "outputTokens": 3200,
    "computeTime": 5,
    "cost": 0.0124
  }
}

Complete Event Reference Table

Event TypeRESTWebSocketDescription
agentLive agent reasoning
actionBrowser action performed
response_updateStatus updates
task_completed✓ (poll)Task finished successfully
guardrail_trigger✓ (poll)Human input needed
error✓ (poll)Task failed
end_sessionSession terminated
instance:disconnectedInstance connection lost
instance:reconnectedInstance recovered

Next Steps