Qubitz API Documentation

WebSocket API endpoints for AI-powered research, chat, multi-agent architecture generation, deployment, and API key management.

Overview

The Qubitz API provides WebSocket endpoints for AI-powered research, chat, multi-agent architecture generation, deployment, and API key management. All endpoints stream real-time responses over WebSocket connections.

Base URL: wss://api.qubitz.ai


Authentication

Getting API Keys

API keys are provisioned through the Qubitz platform. Sign in at qubitz.ai and navigate to your project settings to generate keys.

There are two key scopes:

ScopePrefixEndpoints
UCTqk_uct_/research, /chat
ControlHubqk_ch_/getspec, /updatespec, /deploy, /createapikey, /deleteapikey

Authenticating Requests

Pass your API key as a query parameter or as an x-api-key header when connecting:

wss://api.qubitz.ai/<endpoint>?api_key=<your_api_key>

or

x-api-key: <your_api_key>

If the key is missing, invalid, or lacks the required scope, the connection is rejected with WebSocket close code 1008.


Endpoints

POST /research

Run an AI-powered deep research pipeline on any topic. A multi-agent system performs web research, synthesizes findings, identifies AI use cases for the given company, and produces a comprehensive research report with executive summary, market analysis, and actionable recommendations. Outputs are uploaded to S3 as both Markdown and PDF, along with a scored list of AI use cases tailored to the company.

Scope: UCT

Connect: wss://api.qubitz.ai/research?api_key=qk_uct_...

Request Payload

{
  "prompt": "Latest AI Trends 2026",
  "company_name": "TestCompany",
  "company_url": "https://example.com/",
  "user_id": "user123",
  "session_id": "session456"
}
FieldTypeRequiredDescription
promptstringYesResearch topic or query
company_namestringYesCompany name for focused research
company_urlstringYesCompany website URL
user_idstringYesYour user ID
session_idstringYesSession identifier

Response Stream

Messages arrive in this general order:

1. Progress Updates

{ "type": "status", "message": "Starting multi-agent research system...", "session_id": "..." }

2. Agent Progress

{ "type": "multiagent_step", "step": "research", "message": "Researching sources...", "session_id": "..." }
{ "type": "multiagent_progress", "step": "analysis", "session_id": "..." }

3. S3 Upload Notifications

{
  "type": "s3_upload_complete",
  "file_type": "deep_research_markdown",
  "s3_url": "https://qubitz-research-reports.s3.amazonaws.com/.../report.md",
  "session_id": "..."
}

Possible file_type values: markdown, pdf, deep_research_markdown, deep_research_pdf, AI_discovery_markdown, AI_discovery_pdf, use_cases_pdf, use_cases_md

4. Use Cases

{
  "type": "use_cases_complete",
  "use_cases": [
    {
      "id": "uc_1",
      "title": "Quantum-Safe Payment Processing",
      "description": "...",
      "business_value": "...",
      "impact_score": "High",
      "implementation": "...",
      "estimated_roi": "...",
      "alignment_score": "High"
    }
  ],
  "total_use_cases": 5,
  "session_id": "..."
}

5. Completion

{
  "type": "complete",
  "project_id": "project21",
  "user_id": "user123",
  "s3_deep_research_report_url": "https://...",
  "s3_deep_research_pdf_url": "https://...",
  "s3_AI_discovery_report_url": "https://...",
  "s3_AI_discovery_pdf_url": "https://...",
  "s3_use_cases_pdf_url": "https://...",
  "s3_use_cases_md_url": "https://...",
  "all_s3_urls": {
    "deep_research_report_url": "https://...",
    "deep_research_pdf_url": "https://...",
    "AI_discovery_report_url": "https://...",
    "AI_discovery_pdf_url": "https://...",
    "use_cases_pdf_url": "https://...",
    "use_cases_md_url": "https://..."
  },
  "session_id": "..."
}

Keepalive (periodic, during long operations):

{ "type": "keepalive", "timestamp": 1710000000, "message": "Processing..." }

Error:

{ "type": "error", "error": "INVALID_QUERY", "message": "Query validation failed: ...", "session_id": "..." }

POST /chat

Have a conversational Q&A session about a previously generated research report. The AI reads the full report (from S3 or raw text) and answers follow-up questions, summarizes sections, extracts insights, or performs additional web searches when needed. Supports multi-turn conversations with session-based token tracking.

Scope: UCT

Connect: wss://api.qubitz.ai/chat?api_key=qk_uct_...

Request Payload

{
  "messages": [
    { "role": "user", "content": "Summarize the key findings from the report" }
  ],
  "s3_report_url": "https://qubitz-research-reports.s3.amazonaws.com/.../report.md",
  "user_id": "user123",
  "session_id": "session456",
  "project_id": "project21"
}
FieldTypeRequiredDescription
messagesarrayYesConversation messages (role: "user" or "assistant")
user_idstringYesYour user ID
session_idstringYesChat session identifier
s3_report_urlstringYes*S3 URL of the research report
reportstringYes*Raw markdown content of the report
project_idstringNoProject identifier
company_namestringNoCompany name context
token_limitnumberNoMax token limit (default: 250000)

*Provide either s3_report_url or report, not both.

Response Stream

1. Status

{ "type": "chat_status", "message": "Processing chat request...", "session_id": "..." }

2. Streaming Response

{ "type": "chat_chunk", "chunk": "The report highlights three key...", "is_final": false, "session_id": "..." }

Chunks arrive sequentially. Concatenate all chunk values to build the full response.

3. Completion

{
  "type": "chat_complete",
  "success": true,
  "response": {
    "metadata": {
      "tools_used": {
        "web_search": ["query1", "query2"],
        "report_generated": { "success": false }
      }
    },
    "token_usage": {
      "input_tokens": 15000,
      "output_tokens": 2000,
      "total_tokens": 17000
    }
  },
  "session_info": {
    "user_id": "user123",
    "session_id": "session456",
    "message_count": 3,
    "token_usage": {
      "input_tokens": 15000,
      "output_tokens": 2000,
      "total_tokens": 17000,
      "limit": 250000,
      "limit_reached": false
    }
  }
}

Error:

{ "type": "chat_error", "error": "TOKEN_LIMIT_EXCEEDED", "message": "...", "session_id": "..." }

POST /getspec

Generate a complete multi-agent architecture specification from a use case. Given a use case name, description, and optionally a research report for context, the AI designs an end-to-end agent system - defining each agent's role, model, system prompt, tools, and memory strategy, plus a gateway configuration for API access. The resulting spec is saved and can be refined with /updatespec or deployed with /deploy.

Scope: ControlHub

Connect: wss://api.qubitz.ai/getspec?api_key=qk_ch_...

Request Payload

{
  "user_id": "user123",
  "project_id": "project21",
  "use_case_name": "Automated Financial Research Platform",
  "use_case_description": "Investment firms conducting market research face challenges with information accuracy and research scalability.",
  "s3_uri": "https://qubitz-research-reports.s3.amazonaws.com/.../report.md"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier
use_case_namestringYesName of the use case
use_case_descriptionstringYesDetailed description of the use case
s3_uristringNoS3 URL of a research report for additional context
session_idstringNoSession identifier

Response Stream

1. Status

{ "type": "status", "data": { "message": "Generating architecture specification..." } }

2. Streaming Spec

{ "type": "claude_chunk", "chunk": "Based on the use case..." }

Chunks arrive sequentially. Concatenate all chunk values to build the full spec text.

3. Final Architecture

{
  "type": "architecture",
  "data": {
    "user_id": "user123",
    "project_id": "project21",
    "architecture": {
      "agents_config": {
        "research_agent": {
          "name": "Research Agent",
          "description": "Conducts market research and data gathering",
          "model": "anthropic.claude-sonnet-4-5-20250929-v1:0",
          "prompt": "You are a research agent...",
          "tools": ["web_search", "document_reader"],
          "memory": { "enabled": true, "strategies": ["summary"] }
        },
        "analysis_agent": {
          "name": "Analysis Agent",
          "description": "Analyzes gathered data...",
          "model": "anthropic.claude-sonnet-4-5-20250929-v1:0",
          "prompt": "You are an analysis agent...",
          "tools": ["calculator", "data_viz"],
          "memory": { "enabled": true, "strategies": ["summary"] }
        }
      },
      "gateway_config": { "provider": "api_gateway", "targets": [] }
    },
    "status": "pending"
  }
}

Keepalive:

{ "type": "keepalive", "data": { "message": "Processing in progress... (15s)", "elapsed_seconds": 15 } }

Error:

{ "type": "error", "data": { "error": "generation_failed", "message": "..." } }

POST /updatespec

Modify an existing multi-agent architecture spec using natural language instructions. Describe what you want to change (e.g., "add a security agent", "switch the research agent to a different model", "remove the analytics agent") and the AI will regenerate the spec with your changes applied while preserving the rest of the architecture.

Scope: ControlHub

Connect: wss://api.qubitz.ai/updatespec?api_key=qk_ch_...

Request Payload

{
  "user_id": "user123",
  "project_id": "project21",
  "user_input": "Add a security agent that validates all API calls and enforces rate limiting"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier (must have an existing spec)
user_inputstringYesNatural language description of the changes

Response Stream

1. Status

{ "type": "status", "data": { "message": "Updating architecture specification..." } }

2. Streaming Update

{ "type": "claude_chunk", "chunk": "Modifying the spec to add..." }

3. Update Confirmed

{ "type": "chat_updates_response", "data": { "spec_updated": true } }

4. Completion

{ "type": "complete" }

POST /deploy

Deploy a generated multi-agent architecture to AWS as a live, production-ready service. The system generates CDK infrastructure code, pushes it to a GitHub repository, and triggers a GitHub Actions CI/CD pipeline that provisions API Gateway, Lambda, and all required AWS resources. You get a live agent_endpoint URL and a GitHub repo with the full source code.

Scope: ControlHub

Connect: wss://api.qubitz.ai/deploy?api_key=qk_ch_...

Request Payload

{
  "user_id": "user123",
  "project_id": "project21"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier (must have an approved spec)
github_usernamestringNoGitHub username to add as collaborator on the repo

Response Stream

1. Deployment Started

{
  "type": "deployment_started",
  "data": {
    "status": "started",
    "message": "Deployment started. Generating infrastructure and pushing to GitHub...",
    "user_id": "user123",
    "project_id": "project21"
  }
}

2. Code Pushed (first deployment_complete)

{
  "type": "deployment_complete",
  "data": {
    "status": "success",
    "deployment_status": "deploying_via_cicd",
    "message": "Code pushed to Qubitz-202/my-app. GitHub Actions is deploying via CDK.",
    "github_repo": "https://github.com/Qubitz-202/my-app",
    "user_id": "user123",
    "project_id": "project21"
  }
}

3. CI/CD Progress

{ "type": "status", "data": { "status": "deploying", "message": "Deploy CDK - Deploy with CDK", "progress_percent": 65 } }

progress_percent goes from 0 to 100. Use this to render a progress bar.

4. Deployment Finished (second deployment_complete)

{
  "type": "deployment_complete",
  "data": {
    "status": "deployed",
    "deployment_status": "deployed",
    "message": "Deployment successful!",
    "agent_endpoint": "https://api.qubitz.ai/my_app/invoke",
    "github_repo": "https://github.com/Qubitz-202/my-app",
    "user_id": "user123",
    "project_id": "project21"
  }
}

5. Done

{ "type": "complete" }

Use deployment_status to differentiate the two deployment_complete messages:

  • "deploying_via_cicd" - code pushed, CI/CD running
  • "deployed" - fully deployed, agent_endpoint is live

Error:

{ "type": "error", "data": { "error": "no_architecture", "message": "No architecture spec found. Generate one first with /getspec." } }

POST /createapikey

Create an API key for your deployed application's API Gateway. After deploying with /deploy, use this to generate keys that grant external consumers access to your agent endpoint. Each key is tied to a usage plan for rate limiting and quota management.

Scope: ControlHub

Connect: wss://api.qubitz.ai/createapikey?api_key=qk_ch_...

Request Payload

{
  "user_id": "user123",
  "project_id": "project21",
  "key_name": "production-key"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier (must be deployed)
key_namestringNoFriendly name for the API key

Response

{
  "type": "api_key_created",
  "data": {
    "api_key_value": "aBcDeFgHiJkLmNoPqRsTuVwXyZ123456",
    "api_key_id": "abc123def",
    "usage_plan_id": "plan456",
    "api_endpoint": "https://api.qubitz.ai/my_app/invoke"
  }
}

Save api_key_id and usage_plan_id - you need them to delete the key later.


POST /deleteapikey

Revoke and delete an API key from your deployed application's API Gateway. Pass the api_key_id (and optionally usage_plan_id) returned from /createapikey to permanently remove access for that key.

Scope: ControlHub

Connect: wss://api.qubitz.ai/deleteapikey?api_key=qk_ch_...

Request Payload

{
  "user_id": "user123",
  "project_id": "project21",
  "api_key_id": "abc123def",
  "usage_plan_id": "plan456"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier
api_key_idstringYesAPI key ID from /createapikey response
usage_plan_idstringNoUsage plan ID from /createapikey response

Response

{
  "type": "api_key_deleted",
  "data": { "api_key_id": "abc123def" }
}

/devguide

Generate a developer guide for your deployed application. The DevGuideAgent runtime produces a comprehensive markdown document covering your application's architecture, agent configurations, API usage, and deployment details.

Scope: Full access only (env-var keys)

Connect: wss://api.qubitz.ai/devguide?api_key=<env_key>

Request Payload

{
  "user_id": "user123",
  "project_id": "project21"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier (must be deployed)

Response Stream

Streams SSE progress events during generation, then returns the final JSON with the markdown content.

Completion

{
  "type": "complete",
  "data": {
    "markdown": "# Developer Guide\n\n## Architecture\n...",
    "project_id": "project21"
  }
}

Note: This endpoint is not accessible with scoped API keys (qk_uct_ or qk_ch_). Only environment-level keys with full access can reach it.


/design-doc - Design Document Generation

Generate a comprehensive Application Design Document (13 sections + 4 appendices) for your deployed application. Accessed via a presigned WebSocket URL.

Protocol: WebSocket (via presigned URL, SignatureV4)

Runtime: DesignDocAgentRuntime

Step 1: Get Presigned URL

POST /api/bedrock-agent/design-doc-websocket-url

Response

{
  "url": "wss://bedrock-agentcore.eu-central-1.amazonaws.com/runtimes/...",
  "runtime_arn": "arn:aws:bedrock-agentcore:...",
  "region": "eu-central-1",
  "expires_in": 3600,
  "auth_method": "query_parameters"
}

Step 2: Connect to WebSocket

Connect directly to the returned url and send your payload.

Request Payload

{
  "user_id": "user123",
  "project_id": "project21"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier (must be deployed)

Response: Streams progress events, then final JSON with the generated design document in markdown and PDF format.


/wafr - Well-Architected Framework Review

Run an AWS Well-Architected Framework Review on your deployed application. This is a synchronous HTTP endpoint, not WebSocket.

Protocol: HTTP (synchronous invocation)

Runtime: WafrAutomationAgentV2Runtime

POST /api/bedrock-agent/wafr

Request Payload

{
  "user_id": "user123",
  "project_id": "project21"
}
FieldTypeRequiredDescription
user_idstringYesYour user ID
project_idstringYesProject identifier (must be deployed)

Response

{
  "success": true,
  "s3_https_uri": "https://... (S3 URL to generated WAFR report)",
  "response": "raw text",
  "parsedResponse": { },
  "timestamp": "2026-04-13T12:00:00.000Z"
}
FieldTypeDescription
successbooleanWhether the review completed successfully
s3_https_uristringS3 URL to the generated WAFR report
responsestringRaw text response from the agent
parsedResponseobjectStructured review findings
timestampstringISO timestamp of completion

Integration

TypeScript

type QubitzMessage = {
  type: string;
  data?: Record<string, any>;
  message?: string;
  chunk?: string;
  [key: string]: any;
};

function connectQubitz(
  endpoint: string,
  apiKey: string,
  payload: Record<string, any>,
  handlers: {
    onMessage?: (msg: QubitzMessage) => void;
    onChunk?: (text: string) => void;
    onComplete?: (msg: QubitzMessage) => void;
    onError?: (msg: QubitzMessage) => void;
    onProgress?: (percent: number, message: string) => void;
  }
): WebSocket {
  const ws = new WebSocket(
    `wss://api.qubitz.ai/${endpoint}?api_key=${apiKey}`
  );

  ws.onopen = () => {
    ws.send(JSON.stringify(payload));
  };

  ws.onmessage = (event) => {
    const msg: QubitzMessage = JSON.parse(event.data);
    handlers.onMessage?.(msg);

    switch (msg.type) {
      // Research chunks
      case "stream_chunk":
        handlers.onChunk?.(msg.data?.chunk ?? "");
        break;

      // Chat chunks
      case "chat_chunk":
        handlers.onChunk?.(msg.chunk ?? "");
        break;

      // Spec generation chunks
      case "claude_chunk":
        handlers.onChunk?.(msg.chunk ?? "");
        break;

      // Deploy progress
      case "status":
        if (msg.data?.progress_percent !== undefined) {
          handlers.onProgress?.(msg.data.progress_percent, msg.data.message);
        }
        break;

      // Completion types
      case "complete":
      case "chat_complete":
      case "deployment_complete":
      case "architecture":
      case "use_cases_complete":
      case "api_key_created":
      case "api_key_deleted":
        handlers.onComplete?.(msg);
        break;

      // Errors
      case "error":
      case "chat_error":
        handlers.onError?.(msg);
        break;
    }
  };

  ws.onerror = (err) => {
    handlers.onError?.({ type: "error", message: "WebSocket error" });
  };

  return ws;
}

Example: Research

const ws = connectQubitz("research", "qk_uct_...", {
  prompt: "Latest AI Trends 2026",
  company_name: "TestCompany",
  company_url: "https://example.com/",
  user_id: "user123",
  session_id: "session456",
}, {
  onChunk: (text) => process.stdout.write(text),
  onComplete: (msg) => {
    if (msg.type === "use_cases_complete") {
      console.log(`\n${msg.use_cases.length} use cases generated`);
    }
    if (msg.type === "complete") {
      console.log("\nReport URLs:", msg.all_s3_urls);
      ws.close();
    }
  },
  onError: (msg) => console.error("Error:", msg.message),
});

Example: Chat

let response = "";

const ws = connectQubitz("chat", "qk_uct_...", {
  messages: [{ role: "user", content: "What are the key findings?" }],
  s3_report_url: "https://qubitz-research-reports.s3.amazonaws.com/.../report.md",
  user_id: "user123",
  session_id: "session456",
  project_id: "project21",
}, {
  onChunk: (text) => { response += text; },
  onComplete: (msg) => {
    if (msg.type === "chat_complete") {
      console.log("Full response:", response);
      console.log("Tokens used:", msg.response.token_usage.total_tokens);
      ws.close();
    }
  },
});

Example: Generate Spec → Deploy

// Step 1: Generate architecture spec
const specWs = connectQubitz("getspec", "qk_ch_...", {
  user_id: "user123",
  project_id: "project21",
  use_case_name: "Financial Research Platform",
  use_case_description: "AI-powered investment research...",
  s3_uri: "https://qubitz-research-reports.s3.amazonaws.com/.../report.md",
}, {
  onComplete: (msg) => {
    if (msg.type === "architecture") {
      console.log("Agents:", Object.keys(msg.data.architecture.agents_config));
      specWs.close();
      deployApp(); // proceed to deploy
    }
  },
});

// Step 2: Deploy
function deployApp() {
  const deployWs = connectQubitz("deploy", "qk_ch_...", {
    user_id: "user123",
    project_id: "project21",
  }, {
    onProgress: (pct, msg) => console.log(`[${pct}%] ${msg}`),
    onComplete: (msg) => {
      if (msg.type === "deployment_complete" && msg.data?.deployment_status === "deployed") {
        console.log("Live at:", msg.data.agent_endpoint);
        deployWs.close();
      }
    },
  });
}

Python

import asyncio
import json
import websockets


async def connect_qubitz(endpoint: str, api_key: str, payload: dict):
    """Connect to a Qubitz WebSocket endpoint and yield messages."""
    url = f"wss://api.qubitz.ai/{endpoint}?api_key={api_key}"

    async with websockets.connect(
        url,
        ping_interval=30,
        ping_timeout=300,
        close_timeout=60,
    ) as ws:
        await ws.send(json.dumps(payload))

        async for raw in ws:
            msg = json.loads(raw)
            yield msg

            if msg.get("type") in ("complete", "error", "chat_error"):
                break

Example: Research

async def run_research():
    async for msg in connect_qubitz("research", "qk_uct_...", {
        "prompt": "Latest AI Trends 2026",
        "company_name": "TestCompany",
        "company_url": "https://example.com/",
        "user_id": "user123",
        "session_id": "session456",
    }):
        match msg["type"]:
            case "status" | "multiagent_step":
                print(f"[{msg['type']}] {msg.get('message', '')}")
            case "s3_upload_complete":
                print(f"Uploaded: {msg['s3_url']}")
            case "use_cases_complete":
                for uc in msg["use_cases"]:
                    print(f"  - {uc['title']} ({uc['impact_score']})")
            case "complete":
                print(f"\nReport: {msg['s3_deep_research_report_url']}")
                print(f"PDF:    {msg['s3_deep_research_pdf_url']}")
            case "error":
                print(f"ERROR: {msg.get('message')}")

asyncio.run(run_research())

Example: Chat

async def chat_with_report():
    full_response = ""

    async for msg in connect_qubitz("chat", "qk_uct_...", {
        "messages": [{"role": "user", "content": "Summarize the key findings"}],
        "s3_report_url": "https://qubitz-research-reports.s3.amazonaws.com/.../report.md",
        "user_id": "user123",
        "session_id": "session456",
        "project_id": "project21",
    }):
        match msg["type"]:
            case "chat_chunk":
                full_response += msg.get("chunk", "")
                print(msg.get("chunk", ""), end="", flush=True)
            case "chat_complete":
                tokens = msg["response"]["token_usage"]["total_tokens"]
                print(f"\n\n--- {tokens} tokens used ---")

asyncio.run(chat_with_report())

Example: Generate Spec + Deploy

async def generate_and_deploy():
    # Step 1: Generate spec
    print("Generating architecture spec...")
    async for msg in connect_qubitz("getspec", "qk_ch_...", {
        "user_id": "user123",
        "project_id": "project21",
        "use_case_name": "Financial Research Platform",
        "use_case_description": "AI-powered investment research...",
        "s3_uri": "https://qubitz-research-reports.s3.amazonaws.com/.../report.md",
    }):
        if msg["type"] == "architecture":
            agents = msg["data"]["architecture"]["agents_config"]
            print(f"Generated {len(agents)} agents: {list(agents.keys())}")
            break

    # Step 2: Deploy
    print("\nDeploying...")
    async for msg in connect_qubitz("deploy", "qk_ch_...", {
        "user_id": "user123",
        "project_id": "project21",
    }):
        match msg["type"]:
            case "status" if "progress_percent" in msg.get("data", {}):
                print(f"  [{msg['data']['progress_percent']}%] {msg['data']['message']}")
            case "deployment_complete":
                data = msg["data"]
                if data.get("deployment_status") == "deployed":
                    print(f"\nLive at: {data['agent_endpoint']}")
                    print(f"GitHub:  {data['github_repo']}")

    # Step 3: Create API key for the deployed app
    print("\nCreating API key...")
    async for msg in connect_qubitz("createapikey", "qk_ch_...", {
        "user_id": "user123",
        "project_id": "project21",
        "key_name": "production-key",
    }):
        if msg["type"] == "api_key_created":
            data = msg["data"]
            print(f"API Key:  {data['api_key_value']}")
            print(f"Key ID:   {data['api_key_id']}")
            print(f"Endpoint: {data['api_endpoint']}")

asyncio.run(generate_and_deploy())

Common Message Types

These message types appear across multiple endpoints:

TypeEndpointsDescription
statusAllProgress update. May contain progress_percent (0-100) for /deploy.
claude_chunk/getspec, /updatespecStreaming text chunk from spec generation. Concatenate chunk values for the full output.
chat_updates_response/updatespecConfirms the spec was updated. Contains { "data": { "spec_updated": true } }.
keepalive/research, /deployPeriodic ping during long operations. No action needed.
completeAllOperation finished. Safe to close the connection.
errorAllSomething went wrong. Contains message with details.

Error Handling

All endpoints can return error messages. Always handle these:

{ "type": "error", "message": "No architecture spec found. Generate one first with /getspec." }

Common error scenarios:

  • Invalid/expired API key - Connection rejected with code 1008
  • Wrong scope - UCT key used on ControlHub endpoint (code 1008)
  • No spec found - Calling /deploy before /getspec
  • Token limit exceeded - Chat session exceeded token budget
  • Query validation failed - Research topic rejected by safety filters

Rate Limits

WebSocket connections have a 60-minute idle timeout. Long-running operations (research, deploy) send keepalive messages to maintain the connection. No explicit rate limit on message frequency.