aq.dev / docs/api

The AQ API

AQ exposes its workspaces as a programmatic surface: a versioned REST API, signed webhooks, and an MCP server. Anything your team does from the dashboard (create a workspace, watch its events, grab the preview URL, track the PR) a script or an agent can do with an API key.

Authentication

Create an API key in Settings. Keys start with aq_, are shown once, and act as you inside your team: a key sees exactly the workspaces you can see, and it stops working the moment you leave the team. Scopes are set at creation (workspaces:read, workspaces:write, events:read, prs:read, previews:read, webhooks:manage).

curl https://aq.dev/v1/workspaces \
  -H "Authorization: Bearer aq_your_key"

Idempotent writes

Every mutation requires an Idempotency-Key header. Retries with the same key replay the original response instead of re-executing, so a timed-out request can be retried safely:

curl -X POST https://aq.dev/v1/workspaces \
  -H "Authorization: Bearer aq_your_key" \
  -H "Idempotency-Key: create-fix-auth-bug-1" \
  -H "Content-Type: application/json" \
  -d '{"title": "Fix the auth bug", "repo_id": "your-repo-id"}'

Webhooks

Register an https endpoint and AQ notifies it when things happen: workspace.created, workspace.closed, workspace.pr_opened, workspace.pr_merged, workspace.agent_error, and more. Deliveries retry with backoff and are signed so you can verify them:

// aq-signature: t=1700000000,v1=<hex>
const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
const expected = crypto.createHmac("sha256", secret)
  .update(t + "." + rawBody)
  .digest("hex");
// timing-safe compare v1 against expected, and reject stale timestamps

The signing secret is returned once when you create the endpoint. Endpoints that fail continuously are disabled automatically and can be re-created.

MCP

The same surface is available as an MCP server at https://aq.dev/mcp (streamable HTTP), so Claude, Cursor, or any MCP client can list your workspaces, create new ones, read event logs, and fetch preview URLs. Authenticate with the same API key as a Bearer token:

{
  "mcpServers": {
    "aq": {
      "url": "https://aq.dev/mcp",
      "headers": { "Authorization": "Bearer aq_your_key" }
    }
  }
}

Errors and limits

Errors use machine-readable snake_case codes in a stable envelope ({"error": "rate_limited"}), with HTTP status conventions you expect: 401 for a bad key, 403 for a missing scope, 404 for anything not visible to you, 409 while a first attempt is still running, 422 for an idempotency key reused with a different body, and 429 with a Retry-After header when you are rate limited (240 requests per minute per key by default).

Reference

The complete machine-readable reference lives at /v1/openapi.json (OpenAPI 3.1). Endpoints today: workspaces (list, get, create, close), workspace events, pull requests, previews, repos, webhooks, and key introspection at /v1/me.