For AI Agents & Developers

API reference, authentication, webhooks, MCP integration, and the auto-fix loop

Quick Start

Get your API key and submit your first test cycle in under 5 minutes.

1. Get an API Key

Sign in at clawqa.ai with GitHub, then go to Settings → API Keys and generate a key. Keys are prefixed with cqa_.

2. Submit a Test Cycle

curl -X POST https://clawqa.ai/api/v1/test-cycles \
  -H "Authorization: Bearer cqa_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": 1,
    "title": "Login flow regression test",
    "targetUrl": "https://staging.myapp.com",
    "steps": [
      {
        "title": "Login with valid credentials",
        "description": "Navigate to /login, enter valid email and password, click Submit",
        "expectedResult": "User is redirected to dashboard with welcome message"
      },
      {
        "title": "Login with invalid password",
        "description": "Navigate to /login, enter valid email but wrong password, click Submit",
        "expectedResult": "Error message shown: Invalid credentials. Form is not cleared."
      }
    ]
  }'
import requests

response = requests.post(
    "https://clawqa.ai/api/v1/test-cycles",
    headers={"Authorization": "Bearer cqa_your_api_key"},
    json={
        "projectId": 1,
        "title": "Login flow regression test",
        "targetUrl": "https://staging.myapp.com",
        "steps": [
            {
                "title": "Login with valid credentials",
                "description": "Navigate to /login, enter valid email and password, click Submit",
                "expectedResult": "User is redirected to dashboard with welcome message"
            }
        ]
    }
)
print(response.json())  # {"id": 42, "status": "submitted"}
const response = await fetch("https://clawqa.ai/api/v1/test-cycles", {
  method: "POST",
  headers: {
    "Authorization": "Bearer cqa_your_api_key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    projectId: 1,
    title: "Login flow regression test",
    targetUrl: "https://staging.myapp.com",
    steps: [
      {
        title: "Login with valid credentials",
        description: "Navigate to /login, enter valid email and password, click Submit",
        expectedResult: "User is redirected to dashboard with welcome message"
      }
    ]
  })
});
const cycle = await response.json();
console.log(cycle); // { id: 42, status: "submitted" }

Authentication

All authenticated endpoints require a Bearer token in the Authorization header:

Authorization: Bearer cqa_your_api_key

API keys:

Unauthenticated requests to protected endpoints return 401 Unauthorized.

Creating Test Cycles

A test cycle represents a batch of test steps to be executed by human testers. Send a POST request to /api/v1/test-cycles:

POST /api/v1/test-cycles
Content-Type: application/json
Authorization: Bearer cqa_...

{
  "projectId": 1,
  "title": "Checkout flow — v2.3.1",
  "targetUrl": "https://staging.myapp.com",
  "steps": [
    {
      "title": "Add item to cart",
      "description": "Search for 'wireless headphones', click first result, click 'Add to Cart'",
      "expectedResult": "Cart badge shows 1 item. Toast notification confirms addition."
    },
    {
      "title": "Complete checkout",
      "description": "Click cart icon, click 'Checkout', fill in test payment details, click 'Place Order'",
      "expectedResult": "Order confirmation page shown with order number and estimated delivery date."
    }
  ]
}

Response:

{
  "id": 42,
  "projectId": 1,
  "title": "Checkout flow — v2.3.1",
  "status": "submitted",
  "stepsCount": 2,
  "createdAt": "2026-02-20T01:30:00Z"
}

The cycle is immediately routed to testers. You'll receive webhook events as results come in.

Receiving Results

Register a Webhook

POST /api/v1/webhooks
Authorization: Bearer cqa_...

{
  "url": "https://your-agent.example.com/clawqa-webhook",
  "events": ["bug_report.created", "bug_report.verified", "bug_report.fix_failed", "cycle.completed"],
  "secret": "whsec_your_signing_secret"
}

Webhook Payload: bug_report.created

{
  "event": "bug_report.created",
  "timestamp": "2026-02-20T03:15:00Z",
  "data": {
    "id": 101,
    "cycleId": 42,
    "title": "Checkout button unresponsive on iOS Safari",
    "severity": "critical",
    "description": "Tapping 'Place Order' does nothing on iPhone 15 Pro, iOS 17.3, Safari.",
    "stepsToReproduce": "1. Open staging URL on iPhone\n2. Add item to cart\n3. Proceed to checkout\n4. Fill payment details\n5. Tap 'Place Order'\n6. Nothing happens",
    "screenshotUrl": "https://clawqa.ai/uploads/bug-101-screenshot.png",
    "device": "iPhone 15 Pro",
    "os": "iOS 17.3",
    "browser": "Safari 17.3"
  }
}

Webhook Payload: bug_report.verified

{
  "event": "bug_report.verified",
  "timestamp": "2026-02-20T04:30:00Z",
  "data": {
    "id": 101,
    "cycleId": 42,
    "fixAttemptId": 5,
    "status": "verified",
    "verifiedBy": "human_tester",
    "notes": "Fix confirmed — Place Order button now works correctly on iOS Safari."
  }
}

The Auto-Fix Loop

When your agent receives a bug_report.created webhook, it enters the fix loop:

🐛 Receive Bug 🔍 Analyze ✍️ Write Fix 🚀 Deploy 📤 Submit Fix ✅ Verified? Pass → Done

Submit a fix:

POST /api/v1/bugs/101/fix
Authorization: Bearer cqa_...

{
  "commitUrl": "https://github.com/myorg/myapp/commit/abc123",
  "deployUrl": "https://staging.myapp.com",
  "notes": "Fixed iOS Safari touch event handler — was using click instead of pointerdown"
}

ClawQA will automatically request re-testing from Applause. If the fix passes, you receive a bug_report.verified webhook. If it fails, you receive bug_report.fix_failed with tester notes, and the loop continues.

MCP Integration

Coming Soon

ClawQA will expose an MCP (Model Context Protocol) server, allowing AI agents to interact with the platform using the emerging standard for AI tool integration.

MCP Server URL

https://clawqa.ai/mcp

Available Tools

clawqa.list_projects()                              → [{id, name, slug, url}]
clawqa.list_cycles(projectId?)                      → [{id, title, status, bugs}]
clawqa.create_cycle(projectId, title, url, steps[]) → {id, status}
clawqa.get_bugs(cycleId)                            → [{id, title, severity, steps}]
clawqa.submit_fix(bugId, commitUrl, deployUrl)      → {status}
clawqa.escalate(cycleId, reason?)                   → {applauseCycleId}

MCP gives agents a structured way to discover and call ClawQA tools without needing to know the REST API details.

OpenClaw Skill Example

Here's a complete example of an OpenClaw skill that integrates with ClawQA:

// clawqa-testing-skill.js — OpenClaw Skill
const CLAWQA_API = "https://clawqa.ai/api/v1";
const API_KEY = process.env.CLAWQA_API_KEY;

// Create a test cycle from a PR
async function createTestCycleFromPR(projectId, prData) {
  const steps = analyzePRForTestSteps(prData);
  const response = await fetch(`${CLAWQA_API}/test-cycles`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      projectId,
      title: `PR #${prData.number}: ${prData.title}`,
      targetUrl: prData.deployUrl,
      steps
    })
  });
  return response.json();
}

// Analyze PR diff to generate test steps
function analyzePRForTestSteps(prData) {
  return prData.changedFiles.map(file => ({
    title: `Verify changes in ${file.path}`,
    description: `Test the functionality affected by changes to ${file.path}. ` +
      `${file.additions} lines added, ${file.deletions} lines removed.`,
    expectedResult: "Feature works correctly with no regressions."
  }));
}

// Handle incoming bug webhook
async function handleBugWebhook(event) {
  if (event.event !== "bug_report.created") return;
  const bug = event.data;
  console.log(`Bug received: ${bug.title} (${bug.severity})`);

  const fix = await analyzeBugAndFix(bug);
  if (fix) {
    await fetch(`${CLAWQA_API}/bugs/${bug.id}/fix`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        commitUrl: fix.commitUrl,
        deployUrl: fix.deployUrl,
        notes: fix.description
      })
    });
    console.log(`Fix submitted for bug ${bug.id}`);
  }
}

module.exports = { createTestCycleFromPR, handleBugWebhook };