Build on the GoodQA API.
A typed REST API and an MCP server for agents. File issues, generate test plans, run missions, and export to GitHub — all programmatically, with the same tenancy and RBAC guarantees as the app.
Create an API key
API keys authenticate agents and the MCP server. Generate one from Settings → API keys in your organization. Keys look like bt_<prefix>_<secret> and carry independent read/write and per-resource scopes. Pass them in the Authorization header — the same header a bearer JWT uses. An issue created with an API key is automatically recorded as agent/API-created with that key's id; a user session (JWT or browser cookie) is recorded as manual. These fields are server-controlled and cannot be supplied in an issue request.
Issue provenance is automatic. A write made with an API key is recorded as an agent/API-created issue with that key's attribution; a browser or other user session is recorded as human-created. The create endpoint never accepts a client-supplied source or attribution id.
Go to SettingsQuickstart
Authenticate and file an issue
Log in for a user-session token (or use an organization API key directly), then create an issue in a project. The server derives creator provenance from that credential; every write endpoint validates against the same Zod schemas the app uses.
curl -s https://goodqa.app/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"you@company.com","password":"••••••••"}'
# → { "user": {...}, "tokens": { "accessToken": "ey…", "refreshToken": "…" } }curl -s https://goodqa.app/v1/projects/$PROJECT_ID/issues \
-H "Authorization: Bearer $BUGTRACKER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"title": "Checkout button unresponsive on mobile",
"type": "bug",
"status": "triage",
"priority": "high",
"severity": "major",
"reproSteps": "1. Open /cart on iOS Safari\n2. Tap Checkout",
"expected": "Navigates to payment",
"actual": "Nothing happens"
}'Issue lists
Search and paginate without losing results
Use search for title and description search; q is an exact alias. Set limit from 1 to 100. When a response includes nextCursor, send it unchanged as cursor on the next request with every active filter repeated. A different q and search, or any offset, page, or skip returns HTTP 400 instead of silently restarting at page one. Use audience for server-derived creator/ownership slices, or createdViaApiKeyId and assignedAgentApiKeyId for an exact agent identity. Every response includes full authorised-result counts, independent of the cursor and active audience filter.
curl -s \
"https://goodqa.app/v1/projects/$PROJECT_ID/issues?search=checkout&limit=100" \
-H "Authorization: Bearer $BUGTRACKER_API_KEY"
# → { "issues": [...], "nextCursor": "eyJ...", "counts": { "total": 42, ... } }
# When nextCursor is non-null, pass it back unchanged as cursor and repeat every active filter.
curl -s --get https://goodqa.app/v1/projects/$PROJECT_ID/issues \
-H "Authorization: Bearer $BUGTRACKER_API_KEY" \
--data-urlencode 'limit=100' \
--data-urlencode 'search=checkout' \
--data-urlencode 'audience=agent_or_api_created' \
--data-urlencode "cursor=$NEXT_CURSOR"Every issue list also accepts one audience filter: human_created, agent_or_api_created, assigned_to_me, or created_by_me. Responses include counts for all five choices before the audience filter or cursor is applied, limited to the caller's authorized result set.
Agents
Model Context Protocol
Drive GoodQA from Claude, Cursor, or any MCP-compatible client — the same tenancy and permission rules as the app itself.
Remote server — recommended
Download .mcpbWorks with Claude Desktop and any client that speaks Streamable HTTP MCP. Open the downloaded .mcpb file (Claude Desktop → Settings → Extensions), then run the command below once from a terminal — it prints a short code and a link. Open the link, sign in, pick which organization to grant, and approve. No API key to copy or store yourself.
unzip the downloaded goodqa.mcpb, then run: node bundle.js pairEndpoint: /v1/mcp — authenticated the same way as any GoodQA API key, scoped to the org and role you approve.
Agents that talk to people: read the conversations skill first (bot identification, specific questions, untrusted replies, escalation) at /v1/meta/agent-skill, or over MCP as resource goodqa://skills/conversations.
Local server (repo checkout)
Running this repo directly? goodqa-mcp is a stdio server over the API, authenticated with a manually created API key — exposes tools for issues, test plans, missions, and more.
claude mcp add bugtracker \
-e BUGTRACKER_API_KEY=... \
-e BUGTRACKER_API_URL=https://goodqa.app \
-- pnpm --filter goodqa-mcp startOn by default
Capabilities switchable per organization
Every capability here is on by default for every organization, on every plan. GoodQA can switch one off for an organization; then its routes answer 404 and its MCP tools are not listed. A capability that needs infrastructure the server does not have yet (custom data needs its database cluster) answers 501 not_configured instead.
Chat questions
On by defaultAsk a multiple-choice question in chat; people answer with buttons and an optional free-text reply.
Switch:
chat.questionsMCP: chat_ask, chat_get_answers
Secret requests
On by defaultAsk a member for a password or API key; they type it into a masked form that stores it in the vault for you alone.
Switch:
vault.requests,vaultRequests.enabledMCP: request_secret, read_requested_secret
Attachment sharing
On by defaultShare links to a file (team only, anyone with the link, or named people), Forward a file into other conversations, and an org policy for public links.
Switch:
attachments.sharingMCP: attachment_share_link, attachment_list_shares, attachment_revoke_share, attachment_forward
Agent knowledge
On by defaultDurable facts, decisions and how-tos for agents, with history, search and review dates.
Switch:
agentKnowledge.enabledMCP: memory_write, memory_search, memory_list, memory_get, memory_supersede, memory_forget, memory_purge
CRM v2
On by defaultPeople and companies with flags, tags, your own external keys, idempotent upsert and batch upsert, changed-since sync, lifecycles with stage SLAs, relationships and CRM webhooks.
Switch:
crm.api.enabled,crm.v2.records,crm.v2.lifecycles,crm.v2.relationships,crm.v2.webhooksMCP: crm_* (up to 29 tools)
Custom data
On by defaultAn organization's own PostgreSQL tables behind a gated SQL API, with structured row calls, import and export. Needs a database cluster on the server: until then every call answers 501 not_configured and the tools are not listed.
Switch:
customData.enabledMCP: data_status, describe, query, find_rows, insert_rows and 7 more
Outreach
On by defaultPermit-gated contact of published business contacts: suppressions, kill switch, policy caps, templates, sequences, webhooks, and Gmail, Microsoft 365 and Zoho mailbox connectors. Bots may only make it safer.
Switch:
outreach.enabled,outreach.api.enabled,outreach.sequences,outreach.webhooks,outreach.byo,outreach.gmail,outreach.outlook,outreach.zoho,outreach.wizard,outreach.queue,outreach.leads,outreach.outlookNotificationsMCP: outreach_* (18, plus outreach_deliver_send with a mailbox connector, 4 for bring-your-own sender and 5 for the work queue)
Coordinator
On by defaultGoodQA as an agent's source of truth: one bootstrap read at session start (rules, handoff, lanes, inbox, changes) and retry-safe checkpoints. A person runs setup once.
Switch:
coordinator.bootstrapMCP: coordinator_bootstrap, coordinator_checkpoint
Reference
Endpoints
Grouped by resource. All paths are relative to https://goodqa.app/v1. Loaded live from the OpenAPI spec.