Orbit API

  • Tier: Premium, Ultimate
  • Offering: GitLab.com
  • Status: Beta

Use this API to run queries, retrieve schemas, and check cluster health for Orbit.

Endpoint reference

For the full reference of Orbit endpoints, including paths, parameters, and responses, see the interactive API reference. The following sections cover query DSL behavior and worked examples that the generated reference doesn’t show.

Query mode

The availability of GQL query mode is controlled by a feature flag named orbit_gql_queries. For more information, see the history.

Queries require JSON DSL objects by default. Enabling orbit_gql_queries switches queries to read-only GQL strings and discovery to GQL guidance. GQL follows openCypher 9 syntax. The flag targets individual users. REST and MCP callers cannot override the mode through parameters or headers. With the flag enabled, response_format: gql returns query results as a plain-text table.

Skills

Skill endpoints require authentication with the read_api scope. They don’t check the Orbit license, so unavailable skills return 404 Not Found instead of 403 Forbidden. The response is 404 Not Found with the message Skills are not available when:

  • The knowledge graph service is an older version without skill RPCs.
  • The knowledge graph service isn’t configured on the instance. On GitLab Self-Managed, this is controlled by orbit.enabled in gitlab.yml, or the legacy knowledge_graph.enabled setting.
  • The current user doesn’t have at least the Reporter role in a group whose top-level group has Orbit turned on. Administrators in Admin Mode and auditors are exempt from this role requirement.

In these cases, the Orbit CLI uses its embedded local skill.

List deployed skills

Lists the Orbit skills deployed with the connected knowledge graph service.

GET /orbit/skills

This request takes no attributes.

If successful, returns 200 OK and the following response attributes:

Attribute Type Description
server_version string Version of the deployed knowledge graph service.
skills array Deployed skills.
skills[].compatibility string Environment requirements from the skill manifest.
skills[].description string Description from the skill manifest.
skills[].name string Skill name.
skills[].version string Skill version from the manifest.

The response includes an ETag header derived from the sorted skill names and versions, and a Cache-Control header set to private, max-age=0, must-revalidate.

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/orbit/skills"

Example response:

json
{
  "skills": [
    {
      "name": "orbit",
      "version": "0.29.0",
      "description": "Use the glab orbit CLI for knowledge graph queries.",
      "compatibility": "Requires Orbit CLI"
    }
  ],
  "server_version": "0.31.0"
}

Retrieve a deployed skill

Retrieves a complete deployed Orbit skill tree.

GET /orbit/skills/:name

Supported attributes:

Attribute Type Required Description
name string Yes Skill name.

If successful, returns 200 OK and the following response attributes:

Attribute Type Description
compatibility string Environment requirements from the skill manifest.
files array Files in the skill tree.
files[].content string UTF-8 file content.
files[].path string Normalized path relative to the skill root.
files[].sha256 string SHA-256 hash of the file content.
name string Skill name.
server_version string Version of the deployed knowledge graph service.
version string Skill version.

The response includes these headers:

Header Description
Cache-Control Set to private, max-age=0, must-revalidate.
ETag Set to "<version>".

Send the current ETag value in the If-None-Match request header to revalidate a cached skill tree. A matching value returns 304 Not Modified with no response body.

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/orbit/skills/orbit"

Example response:

json
{
  "name": "orbit",
  "version": "0.29.0",
  "compatibility": "Requires Orbit CLI",
  "server_version": "0.31.0",
  "files": [
    {
      "path": "SKILL.md",
      "sha256": "93f2655e8772217e4aa8c8fbe3ad0c1f36b2bdf4a63f9f6e2f6d89a3b01da9f8",
      "content": "# Orbit skill\n"
    }
  ]
}

If the skill doesn’t exist, returns 404 Not Found with the known skill names in the error message.

Check deployed skill metadata

Checks the identity and cache headers of a deployed skill without retrieving its files.

HEAD /orbit/skills/:name

Supported attributes:

Attribute Type Required Description
name string Yes Skill name.

If successful, returns 200 OK, the same ETag and Cache-Control headers as GET /orbit/skills/:name, and no response body.

Example request:

shell
curl --head \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/orbit/skills/orbit"

Retrieve a deployed skill file

Retrieves one file from a deployed skill as raw UTF-8 text. Use this route to fetch SKILL.md directly or follow relative links to files in the same skill tree.

GET /orbit/skills/:name/*path

Supported attributes:

Attribute Type Required Description
name string Yes Deployed skill name.
path string Yes File path relative to the skill root, for example references/usage.md.

If successful, returns 200 OK with the file content, not a JSON object. Markdown files (.md) have the content type text/markdown; charset=utf-8. Other files have the content type text/plain; charset=utf-8; no skill file is served as HTML. Only exact paths listed in the skill manifest are available. Unknown paths return 404 Not Found. Malformed paths can return 400 Bad Request. API error responses are JSON, rather than raw file content; requests blocked by path traversal middleware can return a plain-text error.

The response includes a strong ETag from the file’s SHA-256 and a Cache-Control header set to private, max-age=0, must-revalidate. Send the ETag in If-None-Match to receive 304 Not Modified when the file is unchanged. HEAD returns the same headers without a body.

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/orbit/skills/orbit/SKILL.md"

Example response:

markdown
# Orbit skill

Named queries

Prefer POST /api/v4/orbit/query/:name over POST /api/v4/orbit/query for programmatic consumers. A named query’s structure lives on the server, so it cannot drift from the DSL grammar or ontology. Named requests keep JSON envelopes and run templates in the active mode.

Query templates

The named query templates listed at GET /api/v4/orbit/query/templates include raw_query rendered for the authenticated user:

  • Templates contain JSON objects in JSON mode and GQL strings in GQL mode.
  • Identity values, like the ID of the authenticated user, are resolved server-side from the request credentials. The same request returns different raw_query values for different users. Do not cache or share templates across users or modes.
  • Invoke parameterized queries by name with their arguments, as the catalog excludes them.

Prefer executing named queries directly over using templates. Use templates only where displaying the query text is the goal, such as populating a query editor or explorer with the text of a preset.

Query examples

The following examples show the Orbit query DSL for each query type. All examples use POST /api/v4/orbit/query. For the complete query language, see Orbit query language.

In GQL mode, pass a GQL string as the query value to POST /api/v4/orbit/query:

json
{"query": "MATCH (u:User {id: 1}) RETURN u LIMIT 1"}

The examples use the default raw response format. In each response, the result object lists the matched nodes and the edges between them. Node IDs are strings. Aggregation queries also return columns, group_columns, and rows.

Retrieve a user by username:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "query": {
      "query_type": "traversal",
      "nodes": [
        {"id": "u", "entity": "User", "filters": {"username": "john_smith"}}
      ]
    }
  }' \
  --url "https://gitlab.example.com/api/v4/orbit/query"

Example response:

json
{
  "result": {
    "format_version": "5.0.3",
    "query_type": "traversal",
    "nodes": [
      {"type": "User", "id": "1", "username": "john_smith", "name": "John Smith", "state": "active"}
    ],
    "edges": [],
    "pagination": {"has_more": false, "truncated": false}
  },
  "query_type": "traversal",
  "row_count": 1
}

Find merged merge requests in a project:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "query": {
      "query_type": "traversal",
      "nodes": [
        {"id": "p", "entity": "Project", "node_ids": [8]},
        {"id": "mr", "entity": "MergeRequest", "filters": {"state": "merged"}}
      ],
      "relationships": [{"type": "IN_PROJECT", "from": "mr", "to": "p"}]
    }
  }' \
  --url "https://gitlab.example.com/api/v4/orbit/query"

Example response:

json
{
  "result": {
    "format_version": "5.0.3",
    "query_type": "traversal",
    "nodes": [
      {"type": "Project", "id": "8", "name": "Diaspora Client", "full_path": "diaspora/diaspora-client", "visibility_level": "public"},
      {"type": "MergeRequest", "id": "43", "iid": 1, "title": "Resolve connection timeout on large payloads", "state": "merged", "source_branch": "fix-timeout", "target_branch": "main"},
      {"type": "MergeRequest", "id": "44", "iid": 2, "title": "Replace deprecated API calls in federation module", "state": "merged", "source_branch": "update-federation-api", "target_branch": "main"}
    ],
    "edges": [
      {"from": "MergeRequest", "from_id": "43", "to": "Project", "to_id": "8", "type": "IN_PROJECT"},
      {"from": "MergeRequest", "from_id": "44", "to": "Project", "to_id": "8", "type": "IN_PROJECT"}
    ],
    "pagination": {"has_more": false, "truncated": false}
  },
  "query_type": "traversal",
  "row_count": 2
}

Count merge requests per project. Traversal and aggregation queries must bound at least one node with node_ids or filters:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "query": {
      "query_type": "aggregation",
      "nodes": [
        {"id": "p", "entity": "Project", "node_ids": [5, 8]},
        {"id": "mr", "entity": "MergeRequest"}
      ],
      "relationships": [{"type": "IN_PROJECT", "from": "mr", "to": "p"}],
      "aggregations": [{"count": "mr", "as": "mr_count"}],
      "group_by": ["p"]
    }
  }' \
  --url "https://gitlab.example.com/api/v4/orbit/query"

Example response:

json
{
  "result": {
    "format_version": "5.0.3",
    "query_type": "aggregation",
    "nodes": [],
    "edges": [],
    "columns": [{"name": "mr_count", "function": "count", "target": "mr"}],
    "group_columns": [{"name": "p", "kind": "node", "node": "p", "entity": "Project"}],
    "rows": [
      {"p": {"type": "Project", "id": "8", "properties": {"name": "Diaspora Client", "full_path": "diaspora/diaspora-client", "visibility_level": "public"}}, "mr_count": 8},
      {"p": {"type": "Project", "id": "5", "properties": {"name": "Puppet", "full_path": "brightbox/puppet", "visibility_level": "public"}}, "mr_count": 6}
    ],
    "pagination": {"has_more": false, "truncated": false}
  },
  "query_type": "aggregation",
  "row_count": 2
}

Find outgoing neighbors of a user. The direction attribute accepts outgoing, incoming, or both, and defaults to outgoing:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "query": {
      "query_type": "neighbors",
      "nodes": [{"id": "u", "entity": "User", "node_ids": [1]}],
      "neighbors": {"direction": "outgoing"}
    }
  }' \
  --url "https://gitlab.example.com/api/v4/orbit/query"

Example response:

json
{
  "result": {
    "format_version": "5.0.3",
    "query_type": "neighbors",
    "nodes": [
      {"type": "User", "id": "1", "username": "john_smith", "name": "John Smith", "state": "active"},
      {"type": "Group", "id": "29", "name": "diaspora", "full_path": "diaspora", "visibility_level": "public"},
      {"type": "MergeRequest", "id": "43", "iid": "1", "title": "Resolve connection timeout on large payloads", "state": "merged", "source_branch": "fix-timeout", "target_branch": "main"},
      {"type": "MergeRequest", "id": "44", "iid": "2", "title": "Replace deprecated API calls in federation module", "state": "merged", "source_branch": "update-federation-api", "target_branch": "main"}
    ],
    "edges": [
      {"from": "User", "from_id": "1", "to": "Group", "to_id": "29", "type": "MEMBER_OF"},
      {"from": "User", "from_id": "1", "to": "MergeRequest", "to_id": "43", "type": "AUTHORED"},
      {"from": "User", "from_id": "1", "to": "MergeRequest", "to_id": "44", "type": "AUTHORED"}
    ],
    "pagination": {"has_more": false, "truncated": false}
  },
  "query_type": "neighbors",
  "row_count": 3
}

Find the shortest path from a user to a project. Path finding queries require rel_types, and follow each relationship type only in its defined direction, from the from node toward the to node:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "query": {
      "query_type": "path_finding",
      "nodes": [
        {"id": "u", "entity": "User", "node_ids": [1]},
        {"id": "p", "entity": "Project", "node_ids": [8]}
      ],
      "path": {
        "type": "shortest",
        "from": "u",
        "to": "p",
        "max_depth": 3,
        "rel_types": ["MEMBER_OF", "CONTAINS"]
      }
    }
  }' \
  --url "https://gitlab.example.com/api/v4/orbit/query"

Example response:

json
{
  "result": {
    "format_version": "5.0.3",
    "query_type": "path_finding",
    "nodes": [
      {"type": "User", "id": "1", "username": "john_smith", "name": "John Smith", "state": "active"},
      {"type": "Group", "id": "29", "name": "diaspora", "full_path": "diaspora", "visibility_level": "public"},
      {"type": "Project", "id": "8", "name": "Diaspora Client", "full_path": "diaspora/diaspora-client", "visibility_level": "public"}
    ],
    "edges": [
      {"from": "User", "from_id": "1", "to": "Group", "to_id": "29", "type": "MEMBER_OF", "path_id": 0, "step": 0},
      {"from": "Group", "from_id": "29", "to": "Project", "to_id": "8", "type": "CONTAINS", "path_id": 0, "step": 1}
    ],
    "pagination": {"has_more": false, "truncated": false}
  },
  "query_type": "path_finding",
  "row_count": 1
}

Access and cluster health

GET /api/v4/orbit/status always returns 200 OK, regardless of access or service health. When the user has no access, system is null:

json
{
  "user": {
    "available": false
  },
  "system": null
}