API documentation
Everything the app can do, your scripts and agents can do too: plain JSON over HTTPS. Create issues from your tooling, drive a board from CI, or let an AI agent propose work into triage.
Authentication
Create an API key in Settings → API (your org id is shown there too). Send it as a bearer token on every request:
curl -H "Authorization: Bearer ibk_..." \
https://api.issueboard.dev/v1/orgs/{orgId}/issuesKeys come in two shapes, both with an editor (read-write) or viewer (read-only) level:
- Org keys see every project the org role allows.
- Project keys are scoped to a single project — they can only read and write issues of that project, and must pass its
project_idwhen creating. Give agents and integrations the narrowest key that works.
Keys always address the org explicitly in the path — there is no endpoint to discover an org from a key, by design. A key never grants more than the role of the person who created it.
Conventions
Base URL https://api.issueboard.dev/v1. Requests and responses are JSON. Every successful response is wrapped in a data envelope:
{ "data": { "id": "01KT...", "number": 42, "title": "..." } }List endpoints return { items, page, limit, total } inside the envelope and paginate with ?page= and ?limit= (max 500). total is the full filtered count, so you can page honestly. Timestamps are UTC RFC 3339; dates (like due_date) are YYYY-MM-DD; ids are ULIDs.
Issues
/orgs/{o}/issueslist and search/orgs/{o}/issuescreate/orgs/{o}/issues/{number}detail/orgs/{o}/issues/{number}update (editor)/orgs/{o}/issues/{number}delete (editor)List filters: status, assignee, team, project, type_id, priority, label, cycle, customer, sort and free-text q (word-prefix search over title and description).
Create an issue — only title is required:
curl -X POST -H "Authorization: Bearer ibk_..." \
-H "Content-Type: application/json" \
https://api.issueboard.dev/v1/orgs/{orgId}/issues -d '{
"title": "Search returns no results for plurals",
"description": "Markdown **supported**.",
"type": "bug",
"priority": "high",
"project_id": "01KT...",
"due_date": "2026-07-01"
}'type accepts a type name (case-insensitive, resolved within the org) or pass type_id directly — issue types are configurable per org (GET /orgs/{o}/types); omit it for the org default. priority is none | low | medium | high | urgent. Optional references: status_id, team_id, assignee_id, cycle_id, label_ids, and parent_id to file it as a sub-issue of another issue.
Propose instead of place: add "triage_state": "pending" to land the issue in the project's triage inbox for a human to accept — the right default for agents and automations. (Viewer-level keys and reporters always enter triage.)
Updates take the same fields. For safe concurrent edits, send expected_updated_at with the updated_at you last read — the API answers 409 if someone changed the issue in between:
curl -X PATCH -H "Authorization: Bearer ibk_..." \
-H "Content-Type: application/json" \
https://api.issueboard.dev/v1/orgs/{orgId}/issues/42 -d '{
"status_id": "01KT...",
"expected_updated_at": "2026-06-11T10:42:07Z"
}'Triage
/orgs/{o}/triagepending inbox; ?project= or ?unrouted=true/orgs/{o}/issues/{n}/triageaccept / decline / merge (editor)# accept into a project with a starting status
{ "action": "accept", "project_id": "01KT...", "status_id": "01KT..." }
# decline (reporter keeps seeing the outcome in My reports)
{ "action": "decline" }
# merge a duplicate into the canonical issue
{ "action": "merge", "merge_into_number": 17 }Reference data
Everything an issue references is readable (and writable by org-level editor keys) at the obvious places:
/orgs/{o}/statusesboard columns, with category/orgs/{o}/typesconfigurable issue types (icon, color)/orgs/{o}/projects/orgs/{o}/labels/orgs/{o}/members/orgs/{o}/teams/orgs/{o}/customers/orgs/{o}/cycles?state=active|upcoming|pastProject-scoped keys may read these too (they need status and label ids to work) but only ever see issues of their own project.
Attachments
/orgs/{o}/attachmentsmultipart file= (images ≤10 MB, video ≤50 MB)/orgs/{o}/attachments/from-url{ "url": "https://..." } — images only, ≤10 MB/orgs/{o}/attachments/{id}serves the fileUpload first, then embed the returned URL in an issue description or comment as markdown: .
Errors
Errors use conventional HTTP status codes — 400 invalid or missing fields, 401 bad or revoked key, 403 outside the key's scope or level, 404 not found (also returned for resources the key is not allowed to see), 409 conflicts — with a JSON body:
{ "error": { "message": "this API key can only create issues in its scoped project" } }The API is in public beta: we add fields and endpoints without notice but treat renames and removals as breaking. Questions or gaps? support@issueboard.dev.
Comments
/orgs/{o}/issues/{n}/comments/orgs/{o}/issues/{n}/comments{ "body": "markdown" }/orgs/{o}/issues/{n}/comments/{id}author only/orgs/{o}/issues/{n}/comments/{id}author onlyComment (and description) bodies are markdown; image and video attachment URLs embed inline.
@[Name](user:USER_ID)mentions a member and notifies them;#123links to that issue. The issue's activity history is read-only atGET /orgs/{o}/issues/{n}/activities.