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:
| Scope | Prefix | Endpoints |
|---|---|---|
| UCT | qk_uct_ | /research, /chat |
| ControlHub | qk_ch_ | /getspec, /updatespec, /deploy, /createapikey, /deleteapikey |
Authenticating Requests
Pass your API key as a query parameter when connecting:
wss://api.qubitz.ai/<endpoint>?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"
}
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Research topic or query |
company_name | string | Yes | Company name for focused research |
company_url | string | Yes | Company website URL |
user_id | string | Yes | Your user ID |
session_id | string | Yes | Session 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"
}
| Field | Type | Required | Description |
|---|---|---|---|
messages | array | Yes | Conversation messages (role: "user" or "assistant") |
user_id | string | Yes | Your user ID |
session_id | string | Yes | Chat session identifier |
s3_report_url | string | Yes* | S3 URL of the research report |
report | string | Yes* | Raw markdown content of the report |
project_id | string | No | Project identifier |
company_name | string | No | Company name context |
token_limit | number | No | Max 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"
}
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | Your user ID |
project_id | string | Yes | Project identifier |
use_case_name | string | Yes | Name of the use case |
use_case_description | string | Yes | Detailed description of the use case |
s3_uri | string | No | S3 URL of a research report for additional context |
session_id | string | No | Session identifier |
Response Stream
1. Acknowledgment
{
"type": "ack",
"data": { "user_id": "user123", "session_id": "...", "project_id": "project21", "action": "generate", "status": "processing" }
}
2. Streaming Spec Generation
{ "type": "stream_start", "data": { "message": "Generating architecture specification...", "model": "claude-sonnet-4-5-20250929" } }
{ "type": "stream_chunk", "data": { "chunk": "Based on the use case...", "chunk_index": 0 } }
{ "type": "stream_end", "data": { "total_chunks": 42, "completion_time": 8.5 } }
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"
}
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | Your user ID |
project_id | string | Yes | Project identifier (must have an existing spec) |
user_input | string | Yes | Natural language description of the changes |
Response Stream
Same message types as /getspec: ack → stream_start → stream_chunk → stream_end → architecture
The returned architecture contains the full updated spec.
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"
}
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | Your user ID |
project_id | string | Yes | Project identifier (must have an approved spec) |
github_username | string | No | GitHub 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_endpointis 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"
}
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | Your user ID |
project_id | string | Yes | Project identifier (must be deployed) |
key_name | string | No | Friendly 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"
}
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | Your user ID |
project_id | string | Yes | Project identifier |
api_key_id | string | Yes | API key ID from /createapikey response |
usage_plan_id | string | No | Usage plan ID from /createapikey response |
Response
{
"type": "api_key_deleted",
"data": { "api_key_id": "abc123def" }
}
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:
| Type | Description |
|---|---|
keepalive | Periodic ping during long operations. No action needed. |
error | Something went wrong. Contains message with details. |
complete | Operation finished. Safe to close the connection. |
status | Progress update. May contain progress_percent (0-100) for deploy. |
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
/deploybefore/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.