API
The BugPort API is the programmatic surface behind everything the product does — the dashboard, the browser extension, the NPM widget, and the MCP bridge all talk to it. This page is an overview: it explains the base URL, the three ways callers authenticate, the main resource groups you'll work with, the media upload flow, and how to decide between the API, the widget, and MCP. The full per-endpoint reference (request and response schemas for every path) is being published separately; treat the examples here as illustrative shapes, not a contract.
v0.2.0 The OpenAPI contract is versioned and stable enough to build against, but field-level schemas may still gain optional properties. Pin to the /v1 prefix and code defensively against unknown fields.
Base URL and versioning
https://api.bugport.dev/v1
Every endpoint lives under the /v1 path prefix. Versioning is done through that path segment — a future breaking revision would ship as /v2 rather than silently changing /v1 responses. When you point the widget or a self-hosted client at a non-default host, the base URL must still end in /v1; a missing version segment is the most common cause of 404 responses.
apiBaseUrl prop) but keep the trailing /v1. The hosted production API is always https://api.bugport.dev/v1.Authentication
BugPort has three distinct callers, and each authenticates differently. The right credential depends on who is calling and what scope of data they should reach.
Bearer token. The backend verifies the JWT and resolves the user's workspace memberships. This is the highest-trust path and reaches everything the signed-in user is permitted to see.bp_pub_… key identifies a project and is safe to ship in client-side code because it is origin-restricted — submissions are only accepted from the allowed origins configured on the key. It can create bug reports for its project but cannot read or manage data.Bearer token with explicit scopes such as bugs:read and bugs:write. Shown once at creation, revocable, and every call it makes is audit-logged. See MCP.The browser extension authenticates as a signed-in user as well, and uses its own /v1/plugin/… endpoints tuned for capture upload.
Auth model
Every credential resolves to a workspace scope before any data is returned. Access is always scoped — there is no path that crosses workspace boundaries.
Resource groups
The API is organized into a handful of resource groups. These are the real groups in the v0.2.0 contract; the per-endpoint reference will document each path's parameters and response body.
GET /v1/health, GET /v1/version. Useful for monitoring and for confirming your client reaches the right deployment.GET /v1/auth/me returns the current user; POST /v1/auth/sync-profile reconciles the Supabase identity with BugPort's profile during onboarding.GET/POST /v1/bugs, GET/PATCH /v1/bugs/{bug_id}, plus sub-resources for /logs, /network, /comments, /activity, /media, /export, and /share-links. This is where triage, status changes, and comments happen.POST /v1/widget/media/upload-url, POST /v1/widget/media/complete, POST /v1/widget/bugs. These mirror the media flow below, scoped to a single project.POST /v1/media/upload-url, POST /v1/media/complete, GET /v1/media/{media_id}. Binaries go to Cloudflare R2, never through Postgres./v1/bugs/{bug_id}/comments for discussion and PATCH /v1/bugs/{bug_id} for status and severity changes. These also drive the activity timeline./v1/workspaces, /v1/workspaces/{id}/members, /v1/workspaces/{id}/invites, /v1/workspaces/{id}/storage, /v1/projects, and /v1/projects/{project_id}/widget-keys. Workspaces are the isolation and billing boundary; projects group bugs and own widget keys.GET /v1/plans, and under a workspace .../billing, .../billing/checkout, .../billing/portal, .../billing/storage-addons. Billing is workspace storage-based — every plan includes unlimited team members.GET /v1/connectors, POST /v1/connectors/{provider}/oauth/start|callback, POST /v1/connectors/{id}/test. The foundation for pushing bugs into issue trackers — see Integrations.GET /v1/mcp/tools, POST /v1/mcp/tools/invoke, GET /v1/mcp/config, and bug helpers /v1/mcp/bugs/{bug_id}/context and /v1/mcp/bugs/{bug_id}/prompt. The token-authed REST bridge behind MCP.GET /v1/public/share/bug/{share_id} — public, read-only access to a single bug for external sharing, governed by the same display rules as the dashboard.Example requests
These examples use real paths to show the shape of typical calls. Field names in bodies are illustrative — consult the published reference for exact schemas.
List bugs for the authenticated user (dashboard, JWT):
GET /v1/bugs HTTP/1.1
Host: api.bugport.dev
Authorization: Bearer <supabase_session_jwt>
Fetch a single bug's detail:
GET /v1/bugs/{bug_id} HTTP/1.1
Host: api.bugport.dev
Authorization: Bearer <supabase_session_jwt>
Update a bug's status (drives the activity timeline):
curl -X PATCH https://api.bugport.dev/v1/bugs/{bug_id} \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "status": "in_progress" }'
Media upload flow
Screenshots, videos, attachments, HAR files, and heavy debug payloads are stored in Cloudflare R2, not in Postgres. Clients never stream binaries through the API — instead they request a presigned URL, upload directly to R2, and then tell BugPort the upload finished. This keeps the API fast and keeps large media off the database.
- Request a presigned upload URL
Call
POST /v1/media/upload-url(or/v1/widget/media/upload-urlfor widget submissions) describing the file you intend to upload. The response includes a short-lived URL pointing directly at R2.curl -X POST https://api.bugport.dev/v1/media/upload-url \-H "Authorization: Bearer $JWT" \-H "Content-Type: application/json" \-d '{ "filename": "screenshot.png", "content_type": "image/png" }' - Upload the binary directly to R2
Send the file bytes to the presigned URL using the HTTP method it specifies (typically
PUT). The bytes go straight to Cloudflare R2 and never pass through BugPort's API or Postgres.curl -X PUT "<presigned_r2_url>" \-H "Content-Type: image/png" \--data-binary @screenshot.png - Complete the upload
Call
POST /v1/media/complete(or/v1/widget/media/complete) to register the finished object so BugPort can attach it to a bug and generate thumbnails. After this, the media is retrievable viaGET /v1/media/{media_id}.
/v1/plugin/media/upload-url and attachment upload-urls/complete/fail endpoints, with a fail step so partial uploads can be cleaned up.Error model
The API uses standard HTTP status codes, and validation failures return a structured body rather than a bare string. Treat the status code as the primary signal and the body as detail.
| Status | Meaning | Typical cause |
|---|---|---|
400 | Bad request | Malformed payload or invalid parameters. |
401 | Unauthorized | Missing, expired, or invalid credential. |
403 | Forbidden | Valid credential, but out of scope — e.g. a widget key submitting from a disallowed origin, or a token reaching another workspace. |
404 | Not found | Unknown resource, or a base URL missing the /v1 prefix. |
422 | Validation error | Request shape is understood but fails field validation; the body describes which fields. |
429 | Too many requests | Rate limited. |
5xx | Server error | Retry with backoff; check GET /v1/health. |
A 403 almost always means a scoping problem, not a typo: the credential is valid but is not allowed to reach that data.
When to use API vs widget vs MCP
There are three ways to get data in and out of BugPort. Pick by who is calling and what they need to do.
Use the public widget key when you want end users of a web app to file reports in-product. Submit-only, origin-restricted, safe in client-side code. See the NPM widget.
Use the Supabase JWT for full dashboard-grade access — building internal tools, scripting triage, exporting data, or managing workspaces and projects on behalf of a signed-in user.
Use a scoped MCP token when an AI tool should read and act on bugs from your editor — triage, fix-prompt generation, status updates. Scoped, revocable, audited. See MCP.
A quick rule of thumb: widget is for collecting reports from users, the JWT API is for operating BugPort programmatically, and MCP is for letting AI assistants work with your bugs under tight, auditable scope.