Skip to content

API overview

Orbit has a versioned JSON REST API under /api/v1 on your site’s address. The web application uses the same API, so what you can do in the interface you can do over HTTP, with the same permissions.

Your first request
curl -H "Authorization: Bearer opt_..." \
https://acme.orbit.inortix.com/api/v1/projects

Replace acme.orbit.inortix.com with your company’s address and opt_... with a personal API token.

  • Base path. /api/v1 on your site’s address. The site is taken from the host name, so each company calls its own address.
  • JSON. Property names are camelCase. IDs are strings. Timestamps are ISO 8601.
  • Authentication. Browsers use a session cookie, and scripts use a bearer token. See API authentication.
  • Errors. { "error": "Readable message", "code": "stable_code" }. See the API reference.
  • Stability. /api/v1 changes only by adding routes, optional request fields, response fields and error codes. Removing or renaming something needs a new version of that route first.
  • OpenAPI. GET /openapi.json is public and returns the OpenAPI 3.1 document of the registered routes.

Seventeen resources share one set of conventions:

projects, issues, users, sprints, versions, boards, components, filters, dashboards, workflows, automations, custom-fields, teams, goals, plans, forms, releases.

Request Result
GET /<resource> The visible resources as an array. Lists accept ?projectId=<id> where it applies.
POST /<resource> 201 with the created object
GET /<resource>/:id One object
PATCH /<resource>/:id Merges the fields you send and returns the updated object
DELETE /<resource>/:id 204. 409 while the resource is still referenced.

Server-generated IDs, work item keys, project assignment and timestamps cannot be changed by PATCH. Deleting a user deactivates the account and keeps authorship. Goals use a dedicated versioned API and do not follow the generic PATCH and paging rules.

Many domains also have routes of their own, for example workflows, search, imports, automation and reports. Everything registered is listed in the OpenAPI document.

  • Paging. A generic list answers the whole list unless you give limit (1 to 500). With limit and offset it answers that page with an X-Total-Count header and a Link: <...>; rel="next" header while more remain.
  • Search. GET /search?jql=...&startAt=0&maxResults=100 pages with startAt and maxResults, at most 200 per page. See Search and JQL reference.
  • Optimistic concurrency. If-Unmodified-Since: <updatedAt> makes a stale update fail with 409. Creating operations accept an idempotency key (requestId) so a retry after a lost answer does not create twice.

Example: create a work item and read it back

Section titled “Example: create a work item and read it back”
Create
curl -X POST https://acme.orbit.inortix.com/api/v1/issues \
-H "Authorization: Bearer opt_..." \
-H "Content-Type: application/json" \
-d '{"projectId":"<project id>","summary":"Fix the login redirect","type":"bug"}'
Search
curl -G https://acme.orbit.inortix.com/api/v1/search \
-H "Authorization: Bearer opt_..." \
--data-urlencode 'jql=project = ORB AND type = bug ORDER BY updated DESC' \
--data-urlencode 'maxResults=20'

The other products live under their own prefixes on the same address:

Product Prefix Notes
Pulse /api/v1/pulse/* and /otlp/* Queries, monitors, dashboards, incidents, and OTLP intake
Forge /api/v1/forge/* Repositories, merge requests, pipelines
Folio /api/v1/folio/* Spaces and pages
Lumen /api/v1/lumen/* Status and the MCP endpoint used by agents

The web proxy refuses a signed-in browser’s request to a product the person may not open with 403 product_access_required. Pulse errors are { "error": "..." }, and query syntax errors add position. OTLP endpoints answer errors with a google.rpc.Status body in the request’s encoding.

The REST API, OpenAPI document and typed errors are built. Outgoing webhooks and the GitHub and GitLab integration are in development. See the pages in this section.