REST API and OAuth

Can has a public REST API at https://api.can.randomfact.com. Everything the app can do to boards, tickets, tags, and comments, a script or integration can do too — with the caller's own identity and permissions.

Explore the API

What is available

All endpoints live under /v1 and are scoped by workspace slug:

  • Workspaces — list your memberships, read one workspace.
  • Boards — list, read, create, rename.
  • Columns — list a board's columns.
  • Tickets — list, read, create, edit, bulk status change, semantic search, and slug-free resolution by key (GET /v1/tickets/LAUN-7 finds the ticket across all your workspaces).
  • Tags — full create / rename / recolor / delete.
  • Comments — full thread access including one-level replies and soft-delete.

List endpoints paginate with pageSize (default 50, max 200) and an opaque cursor.

Ticket responses come in two shapes. Reading one ticket — GET .../tickets/{key} or the slug-free GET /v1/tickets/{key} — returns everything: description, attachments, timestamps. Everything else returns a summary: id, boardId, columnId, title, assigneeId, agentAssigneeId, tagIds, commentCount, updatedAt. Creating or editing a ticket answers with that summary rather than echoing the body back; listing and searching add a descriptionPreview of the description's first 160 characters, and take view=full when you really do want every field of every ticket.

Authentication

The API accepts two kinds of credentials for interactive callers:

  • OAuth 2.0 access tokens — for integrations. Can runs a standard OAuth 2.0 / OpenID Connect server on the same hostname: authorization endpoint, token endpoint, and discovery document at /.well-known/openid-configuration. Public clients use PKCE; no client secret is required.
  • Firebase ID tokens — what the Can app itself uses; useful for quick scripts if you already have one.

Two long-lived credentials serve headless callers: personal access tokens (below), and workspace integration credentials — the rfi_can_… token another app's workspace uses to act as itself, described in Integrations.

New OAuth clients can be created two ways:

  • Dynamic client registration (POST /oauth/register, RFC 7591) — programmatic, no manual approval, rate-limited per IP.
  • The Authorize button in the Swagger UI walks you through a browser sign-in for trying out endpoints by hand.

Personal access tokens

For your own scripts, CI jobs, and headless tools there is a third credential: a personal access token (PAT). A PAT is a long-lived opaque token, prefixed rft_can_, that authenticates as you — same identity, same workspace memberships, same permissions as signing in. It is you acting as you: don't hand a PAT to an agent, a connector, or another person; those should keep using OAuth (or a workspace integration credential), so access is delegated and individually revocable.

  • Create one in workspace settings under API tokens (the tokens are personal, not workspace-scoped — the section just lives there). Give it a name and, optionally, an expiry date. The token is displayed exactly once; Can stores only a hash, so copy it immediately.

  • Use it as a standard bearer token:

    curl -H "Authorization: Bearer rft_can_..." \
      https://api.can.randomfact.com/v1/workspaces/my-team/boards
    
  • Revoke it from the same list at any time — revocation is instant, because every request looks the token up live. Expired tokens stop working the moment they expire and are eventually cleaned up automatically.

  • Auditability: changes made with a PAT are recorded in ticket activity with a via value of pat:<token name>, just as OAuth writes record the client name. The field rides along in board exports, and a ticket's History tab shows the name after the actor, as a muted via <token name>.

Permissions

Tokens identify a user, not a workspace. Every request is authorized against your live workspace membership at the moment of the call: if you are removed from a workspace or demoted from admin, the API reflects that on your very next request — no token revocation needed.

The API never reveals whether a workspace you cannot access exists; you get a 404 either way.

Auditability

Changes made through the API are recorded in ticket activity with a via value naming the caller (for example api:My Script for an OAuth client), so a board's export always distinguishes API writes from clicks in the app. Writes that reach the API through the hosted MCP server carry the same client name under an mcp: prefix, so you can tell an agent's edit from a script's. A ticket's History tab shows the name after the actor either way, as a muted via My Script.