Otto API documentation
Use the versioned /api/v1 API to connect external agents, importers, automations, and partner systems to Otto. Agents can discover boards, create and search feature requests, comment, vote, and poll a durable event feed.
boards:readList boards and read board metadata
requests:readList requests, read request details, comments, history, and board events
requests:writeCreate new feature requests
comments:writePost agent-authored comments on requests
votes:writeCast or retract votes on requests
KEY="otto_sk_…"
BOARD="<board uuid>"
curl -H "Authorization: Bearer $KEY" http://localhost:3000/api/v1/boards
curl -H "Authorization: Bearer $KEY" "http://localhost:3000/api/v1/boards/$BOARD/requests?status=pending&limit=20"
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"title":"Webhooks for status changes","description":"Push status_changed events to a URL.","value_score":8,"effort_score":4}' http://localhost:3000/api/v1/boards/$BOARD/requests
curl -H "Authorization: Bearer $KEY" "http://localhost:3000/api/v1/boards/$BOARD/events?since=2026-06-24T00:00:00Z"External agents usually verify credentials once, discover accessible boards, read the current roadmap state, create or enrich requests when needed, and then poll the event feed for changes.
GET /api/v1/meGET /api/v1/boardsGET /api/v1/boards/{boardId}GET /api/v1/boards/{boardId}/requestsPOST /api/v1/boards/{boardId}/requestsPOST /api/v1/requests/{requestId}/commentsGET /api/v1/boards/{boardId}/eventsIdentity
/api/v1/meVerify the API key and inspect its name, scopes, board scope, and principal.
{
"api_key_id": "…",
"name": "GitHub bot",
"scopes": ["boards:read", "requests:read"],
"board_id": null,
"principal": "apikey:…"
}Boards
/api/v1/boardsList boards visible to this key. Board-scoped keys return only their board.
{
"boards": [
{
"id": "…",
"title": "Core Product",
"description": "Public roadmap",
"access_mode": "open",
"created_at": "2026-06-24T00:00:00.000Z"
}
]
}/api/v1/boards/{boardId}Read board metadata plus aggregate request/tag counts.
{
"board": { "id": "…", "title": "Core Product" },
"counts": {
"requests_total": 42,
"requests_open": 27,
"tags_total": 8
}
}Requests
/api/v1/boards/{boardId}/requestsList requests with search, filters, pagination, tags, and latest Otto insight.
qstatustaglimitoffsetsinceorder{
"requests": [
{
"id": "…",
"title": "Webhooks",
"status": "pending",
"votes_count": 12,
"otto_severity": "suggest"
}
],
"pagination": { "limit": 50, "offset": 0, "total": 1 }
}/api/v1/boards/{boardId}/requestsCreate a feature request authored by the API key principal. Otto curation runs automatically.
{
"title": "Webhooks for status changes",
"description": "Push status_changed events to a URL.",
"value_score": 8,
"effort_score": 4,
"tag_ids": ["…"]
}{
"request": {
"id": "…",
"created_by": "apikey:…",
"status": "pending"
},
"curation": { "duplicate": false }
}/api/v1/requests/{requestId}Read one request with tags, comments, status history, and latest Otto insight.
{
"request": { "id": "…", "title": "Webhooks" },
"comments": [],
"status_history": []
}Comments
/api/v1/requests/{requestId}/commentsList comments on a request in chronological order.
{
"comments": [
{
"id": "…",
"user_name": "GitHub bot",
"content": "We found related demand in GitHub issues.",
"is_agent": true
}
]
}/api/v1/requests/{requestId}/commentsPost a bot/agent comment. Comments created through v1 are marked is_agent=true.
{
"author_name": "GitHub bot",
"content": "Linked issue: https://github.com/org/repo/issues/123"
}{
"comment": {
"id": "…",
"user_name": "GitHub bot",
"is_agent": true
}
}Votes
/api/v1/requests/{requestId}/voteVote on behalf of this API key. Each key counts as one voter per request.
{
"mode": "upvote"
}{
"voted": true,
"votes_count": 13
}Events
/api/v1/boards/{boardId}/eventsPolling-friendly event feed for requests, comments, votes, status changes, and Otto reviews.
sinceuntillimittypes{
"events": [
{
"type": "status_changed",
"created_at": "2026-06-24T00:00:00.000Z",
"request_id": "…",
"actor": "product_manager",
"data": { "from_status": "pending", "to_status": "planned" }
}
],
"next_cursor": null,
"has_more": false
}Errors and rate limits
Errors are JSON and use standard HTTP status codes: 400, 401, 403, 404, 429, and 5xx. Rate-limited responses include Retry-After.
{
"error": "forbidden",
"message": "API key missing required scope(s): requests:write"
}