import { Metadata } from "next"; export const metadata: Metadata = { title: "Heartbeads API Docs", description: "Public REST API documentation for Heartbeads", }; export default function ApiDocsPage() { return (
{/* Header */}
← Back to graph

Heartbeads API

Read-only REST API for AI agents, CI/CD bots, and integrations. No authentication required. All endpoints return JSON with CORS headers.

v1 Base path: /api/v1
{/* Table of contents */} {/* Common info */}

Common Details

All responses include CORS headers (Access-Control-Allow-Origin: *) and are cached for 30 seconds.

Every response includes a _meta object with generated_at (ISO 8601), api_version, heartbeads_version, and optional warnings.

Error responses return {`{ "error": "...", "hint": "..." }`} with appropriate HTTP status codes (404, 500).

{/* Authentication */}

Authentication

By default, no authentication is required. When heartbeads is started with --password, all API requests must include the password:

1
Bearer token (recommended)
{`curl -H "Authorization: Bearer " http://localhost:3000/api/v1/graph`}
                  
2
Query parameter
{`curl "http://localhost:3000/api/v1/graph?token="`}
                  

Unauthenticated API requests return 401 with a JSON error. Browser requests are redirected to a login page.


{/* GET /api/v1/graph */}
GET /api/v1/graph

Returns the entire project state in a single response: all issues with comments and claims, dependency edges, summary statistics, and a recent activity feed. This is the primary endpoint for AI agents that need full project context.

Query Parameters

Param Type Default Description
status string all Comma-separated status filter: open,in_progress,blocked,deferred,closed
priority string all Comma-separated priority filter: 0 (critical) to 4 (backlog)
prefix string all Filter by repo prefix (e.g. beads-map)
include string comments,activity Opt-in to expensive fields. Empty string skips both. Omitting returns all.
limit number 50 Activity feed cap (max 200)

Example Request

{`curl http://localhost:3000/api/v1/graph?status=open,in_progress&limit=10`}
          

Response Shape

{`{
  "project": {
    "name": "my-project",
    "prefix": "my-proj",
    "repos": [".", "../backend"],
    "repoUrls": { "my-proj": "https://github.com/org/my-project" }
  },
  "issues": [
    {
      "id": "my-proj-abc",
      "title": "Fix login redirect",
      "description": "Full markdown description...",
      "status": "open",
      "priority": 1,
      "issue_type": "bug",
      "owner": "alice",
      "assignee": "bob",
      "labels": [],
      "created_at": "2025-01-15T10:00:00Z",
      "updated_at": "2025-01-16T14:30:00Z",
      "closed_at": null,
      "close_reason": null,
      "prefix": "my-proj",
      "blockers": ["my-proj-xyz"],
      "dependents": ["my-proj-def"],
      "comments": [
        {
          "author": { "handle": "alice.bsky.social", "did": "did:plc:..." },
          "text": "This needs to be fixed before release",
          "createdAt": "2025-01-16T14:30:00Z",
          "likes": 2,
          "replies": []
        }
      ],
      "claimed_by": {
        "handle": "bob.bsky.social",
        "did": "did:plc:...",
        "claimed_at": "2025-01-16T15:00:00Z"
      }
    }
  ],
  "dependencies": [
    { "from": "my-proj-xyz", "to": "my-proj-abc", "type": "blocks" }
  ],
  "stats": {
    "total": 42, "open": 15, "in_progress": 8,
    "blocked": 3, "closed": 16, "actionable": 12
  },
  "activity": [
    {
      "type": "comment-added",
      "time": "2025-01-16T14:30:00Z",
      "issue_id": "my-proj-abc",
      "issue_title": "Fix login redirect",
      "actor": { "handle": "alice.bsky.social" },
      "detail": "This needs to be fixed..."
    }
  ],
  "_meta": {
    "generated_at": "2025-01-17T09:00:00Z",
    "api_version": "v1",
    "heartbeads_version": "0.3.7"
  }
}`}
          

{/* GET /api/v1/issues/:id */}
GET /api/v1/issues/:id

Returns a single issue with its full description, threaded comments, claim info, and enriched blockers/dependents (each includes title and status so you can understand the blocking context without extra requests).

Path Parameters

Param Description
id The issue ID (e.g. beads-map-abc)

Example Request

{`curl http://localhost:3000/api/v1/issues/beads-map-abc`}
          

Response Shape

{`{
  "issue": {
    "id": "beads-map-abc",
    "title": "Fix login redirect",
    "description": "Full markdown description...",
    "status": "open",
    "priority": 1,
    "issue_type": "bug",
    "owner": "alice",
    "assignee": null,
    "labels": [],
    "created_at": "2025-01-15T10:00:00Z",
    "updated_at": "2025-01-16T14:30:00Z",
    "closed_at": null,
    "close_reason": null,
    "prefix": "beads-map",
    "blockers": [
      { "id": "beads-map-xyz", "title": "Deploy auth service", "status": "in_progress" }
    ],
    "dependents": [
      { "id": "beads-map-def", "title": "Add SSO support", "status": "open" }
    ],
    "comments": [...],
    "claimed_by": null
  },
  "_meta": { ... }
}`}
          

Error Response (404)

{`{
  "error": "Issue not found",
  "hint": "No issue with id \\"nonexistent\\". Use GET /api/v1/graph to list all issues."
}`}
          

{/* GET /api/v1/ready */}
GET /api/v1/ready

Returns issues that are ready to work on: status is open or in_progress and all upstream blockers are closed. Sorted by priority (critical first), then by age (oldest first).

This is the “what should I work on?” endpoint. A Playwright test bot can hit ?type=feature&unclaimed=true to find untested features. A code reviewer can query ?type=bug to find bugs needing review.

Query Parameters

Param Type Default Description
unclaimed boolean false Only return issues with no claim comment
type string all Comma-separated issue type filter: task,bug,feature,chore,epic
assignee string all Filter by assignee handle
prefix string all Filter by repo prefix
limit number all Max issues returned

Example Requests

{`# All actionable issues
curl http://localhost:3000/api/v1/ready

# Only unclaimed bugs
curl "http://localhost:3000/api/v1/ready?unclaimed=true&type=bug"

# Top 5 highest priority
curl "http://localhost:3000/api/v1/ready?limit=5"`}
          

Response Shape

{`{
  "issues": [
    {
      "id": "my-proj-abc",
      "title": "Fix login redirect",
      "status": "open",
      "priority": 0,
      "issue_type": "bug",
      ...
      "comments": [...],
      "claimed_by": null
    }
  ],
  "stats": {
    "total_ready": 12,
    "unclaimed": 8,
    "by_priority": { "0": 2, "1": 5, "2": 3, "3": 2 },
    "by_type": { "bug": 4, "feature": 6, "task": 2 }
  },
  "_meta": { ... }
}`}
          

{/* Use cases */}

Example Use Cases

{[ { agent: "Playwright test bot", endpoint: "GET /api/v1/ready?type=feature&unclaimed=true", desc: "Finds untested features, writes E2E tests", }, { agent: "Code reviewer AI", endpoint: "GET /api/v1/graph?status=in_progress", desc: "Reviews work in progress, posts feedback as comments", }, { agent: "Planning agent", endpoint: "GET /api/v1/graph", desc: "Analyzes the full dependency graph, identifies bottlenecks", }, { agent: "CI/CD bot", endpoint: "GET /api/v1/issues/:id", desc: "Checks a specific issue's status after deployment", }, { agent: "Standup bot", endpoint: "GET /api/v1/graph?include=activity&limit=20", desc: "Summarizes the last 20 activities for daily standup", }, ].map((uc) => (
{uc.agent}
{uc.endpoint}
{uc.desc}
))}
{/* Footer */}
); }