Баунс

API

The public REST API at /api/v1: authentication, choosing a workspace, the exposed namespaces, and the error format.

Bounc's public REST API lives at /api/v1. Its defining property is that it was not written separately: the web app, the CLI, the workers, and this API all speak one contract. The OpenAPI spec is generated from that same contract, so the documented surface and the reachable surface are identical by construction rather than by discipline.

Authentication

A personal access token travels as a bearer credential:

Authorization: Bearer bnp_…

The token acts as the person who created it, across every workspace they belong to.

Choosing a workspace

The workspace is not in the path — a header names it:

HeaderValue
x-workspace-idThe workspace UUID
x-workspace-slugThe workspace code from the address, acme for instance

Either one will do. The token's membership and role are checked against that workspace on every request. Endpoints that act on the user rather than a workspace — listing workspaces, pending invitations — need no header.

A minimal example:

curl https://<your-host>/api/v1/issues \
  -H "Authorization: Bearer bnp_…" \
  -H "x-workspace-slug: acme"

What is exposed

The v1 surface is grouped as the reference groups it:

GroupNamespaces
Workissues, comments, labels, projects, initiatives, teams, search
Agents & automationagents, tasks, chat, skills, autopilots, workflows
Datadatasets, attachments
Workspaceworkspace, members, invitations, users, inbox, pins, dashboard
Integrationsconnectors, credentials
Systemhealth

Three classes stay inside: sign-in and sessions, token management, and everything belonging to the daemon protocol — the last one excluded by the exposure predicate itself, not by configuration.

Conventions

  • Field names are snake_case, timestamps are ISO-8601 with an offset, identifiers are UUIDs.
  • Request bodies are JSON. Most endpoints ignore unknown fields, so a misspelled field name is dropped silently rather than rejected — the value simply does not apply.
  • Some endpoints require a minimum role of member, admin, or owner; the endpoint's description says so.
  • Lists page by cursor. limit is 50 by default and at most 100; the answer carries next_cursor and prev_cursor, passed back as cursor for the next or previous page, and null at either end. There is no offset and no total on a page: counts are their own endpoint. A cursor that is not one the server issued answers page_cursor_invalid; one issued under another order answers page_cursor_stale — read the list again from the top.
  • Issue identifiers are accepted in their human-readable form (ACME-123) wherever the description says they are.

Errors

Every error has one shape, with a matching HTTP status:

{
  "defined": true,
  "code": "NOT_FOUND",
  "status": 404,
  "message": "Not Found",
  "data": { "code": "issue_not_found" }
}
  • code is one of BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, UNPROCESSABLE_CONTENT, TOO_MANY_REQUESTS.
  • data.code is the stable, machine-readable reason — branch on this one.
  • message is for humans and may change over time.

Versioning

The version is part of the path. Within v1, changes are additive only: new endpoints and new optional fields. A breaking revision would ship as /api/v2 with its own spec, so an integration built on v1 keeps working.

Exploring the model

The quickest route is the CLI, which reads the same spec:

bounc schema list                 # which entities exist
bounc schema describe issue       # one entity's operations and fields
bounc schema search assignee      # where a field appears

Next

On this page