REST API
The REST API lets apps, services, scripts, and CI jobs read and update workspace data over HTTP. The base URL is https://onehorizon.ai/api/v1.
Authenticate
| Auth type | Best for |
|---|---|
| Workspace API key | Backend services, internal scripts, CI, sync jobs, and trusted workspace automation. |
| OAuth access token | Apps, MCP clients, and agent integrations that need user-approved workspace access and the signed-in member's identity. |
Agent endpoints only accept OAuth user tokens; see Building Agents.
Make your first request
Create an API key, then list the workspace's tasks. current resolves to the key's workspace, so you do not need a workspace ID:
curl "https://onehorizon.ai/api/v1/workspaces/current/tasks?all=true" \ -H "Authorization: Bearer $ONE_API_KEY" \ -H "X-One-Api-Version: 2"
Send X-One-Api-Version: 2 on every request. Version 2 uses the field names and request schemas in the API reference.
Report bugs and ideas
Create a Triage item with a title and the bearer credential. Both workspace API keys and OAuth tokens derive the default reporter from their bound user.
curl -X POST "https://onehorizon.ai/api/v1/workspaces/current/bugs" \ -H "Authorization: Bearer $ONE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title":"Checkout fails after applying a discount"}'
Ideas use the same request shape:
curl -X POST "https://onehorizon.ai/api/v1/workspaces/current/ideas" \ -H "Authorization: Bearer $ONE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title":"Let customers save multiple shipping addresses", "source":"customer-portal", "priority":"medium", "teamIds":["team_..."], "assigneeIds":["u_..."] }'
Both endpoints return the created task with 201. Optional fields include description, reporterUserId, reportedAt, source, priority, teamIds, assigneeIds, and labels. A malformed request returns 400; missing or invalid credentials return 401; inaccessible workspace context returns 403.
After creation, connect external links through /tasks/{taskId}/work-items, attach a document through /tasks/{taskId}/documents, or request a signed file URL through /files/upload-url.
Pull requests
List, create, and update GitHub pull requests, GitLab merge requests, and Bitbucket pull requests through /api/v1/workspaces/{workspaceId}/pull-requests. Calls use the authenticated member's stored provider token, so repository access matches the connected OAuth grant for each provider.
Creation requires headBranch and baseBranch. The head branch must already exist on the remote, so push it before opening the request. Updates identify a pull request or merge request by provider, repoId, and identifier because numbers are not globally unique across repositories.
Bitbucket pull requests support reviewers by account UUID. Bitbucket does not support labels or assignees, and declined pull requests cannot be reopened through the API.
Documents and files
Document routes list documents by title, type, status, linked task, creator, or updater, and fetch one document body. PUT replaces editable fields on an existing document. PATCH applies ordered text operations such as replace_text, insert_before, insert_after, or delete_text to part of the body without replacing the full content.
For images and videos, request a signed upload URL, upload the file, then use the authenticated asset URL in task descriptions, comments, or documents.
Limits and errors
Responses with bodies are JSON. Successful operations return 200, 201, or 204. Failed requests return an error object with code, message, and a stable errorCode to branch on instead of matching message text.
API keys share one limit per workspace: 200 requests per 15 minutes, with a burst cap of 60 per minute. A 429 response says how many seconds to wait before retrying. Cache stable data instead of polling, and use Webhooks when a service needs to react to changes.
Prefer the JavaScript SDK or Swift SDK when you want generated clients and types instead of hand-written HTTP.