---
title: "Browse the knowledge graph from a node"
method: GET
path: "/connectors/navigate"
tags: ["Connector"]
---

# Browse the knowledge graph from a node

`GET /connectors/navigate`

## Request

- Base URL: `https://app.pipeshub.com/api/v1`
- URL: `https://app.pipeshub.com/api/v1/connectors/navigate`
- Auth: one of:
  - HTTP bearer
  - OAuth 2
    - Authorization code: `/api/v1/oauth2/authorize`
    - Client credentials
    - Token URL: `/api/v1/oauth2/token` scopes: `kb:read`

Open a node in the knowledge graph and see what is inside it — a file
explorer across every connected source.

Call it with no `nodeId` for a flat listing of every record group and
record the caller can reach, newest first. This is a starting point to
pick a node from, not a roster of connected apps — app nodes are not
returned in a listing (except at the root of a limited connected app,
below), though an app's `id` is accepted as a `nodeId` and lists that
app's record groups. Pass a node's `id` to descend:
record groups contain records and folders, and a record contains its
own children — comments, attachments, sub-tasks — plus a `related`
section of cross-referenced records, such as the Confluence page linked
from a Jira ticket. `nodeId` is tolerant: a URL or an issue key such as
`PA-1787` is resolved to its record before navigating, so a link can be
pasted straight in without a separate lookup call.

The response carries a rendered `text` view — breadcrumbs, the current
node, the children listing, `Related:`, and a closing `Next:` line
naming a follow-up call. The structured fields carry the same
information for programmatic use.

**When to use this vs. the other record endpoints:**
- **This endpoint** is for structural exploration — "what is in this
  project", "what is attached to this ticket", "what else links to this
  page". It returns names, types and IDs; it never returns document
  text.
- `GET /connectors/record/{recordId}/content` returns one record's
  actual parsed text. Use it once navigation has identified the record
  you want to read.
- `GET /connectors/record/lookup` is the way in when you hold a URL or
  an issue key rather than a position in the tree.

**Typical flow:** call with no `nodeId` to see what is reachable → pass
a record group's `id` to list its records → take a row whose
`is_record` is true and call
`GET /connectors/record/{recordId}/content` to read it.

**Paging and depth:** results are paginated; `pagination.has_next`
tells you whether to request the next `page`. `depth` above 1 returns
all descendants down to that level as one flat list, each row carrying
its own `level`, instead of only direct children.

**Scope:** everything the caller can read, across both connectors and
Knowledge Base collections. No connector-level filter is applied — the
listing is bounded by per-node permissions, and for a connected app
with a limit by that limit too: no row, breadcrumb or related node
outside it is returned.

**A connected app with a limit:** with no `nodeId`, the root depends
on what the limit names.
- Whole sources (apps or collections) only: the usual flat root,
  every record group and record in those sources.
- Any spaces, folders or files, alone or beside whole sources: one
  row for each whole source, space (record group), folder and file
  the limit names, and nothing from inside them. `pagination.total`
  counts those rows, not the records inside them. `depth` is not
  applied on this call; pass a row's `id` as `nodeId` to open it.

**Permission scoping:**

`rows` and `related` carry only nodes the caller can see, and the
opened node itself is access-checked before any of its details are
returned. A node that does not exist and a node the caller cannot
access are deliberately indistinguishable — both return an empty view
rather than an error.

`breadcrumbs` is the exception: the ancestor trail is resolved by id
alone, without a permission check. For a record shared directly with
the caller, it can therefore name ancestors the caller cannot open.
Treat breadcrumb entries as labels, not as nodes guaranteed to be
navigable.

**A connected app with a limit:** the opened record's `context_block`, and each row's
`context_summary`, names nothing
outside the limit beside the record. Its `External Parent ID` reads
`N/A` for a parent the limit leaves out, and a code file's `Path:`
line is left out unless the limit covers the whole app. Linked
records, related tables, a deal's orgs and products, and live Jira
parent, epic, sub-task and linked-issue lines appear only for
records inside the limit. `Web URL` is kept, though it can contain
folder names.

**Connector and knowledge base nodes:** opening the `id` of a
connector instance the caller has no permission on in the graph (for
example one that has never synced, even for its creator) returns the
same empty view as a missing node. Opening a knowledge base at
`depth` 1 lists nothing; its records appear from `depth` 2.

An OAuth token holding `connector:read` instead of `kb:read` is accepted too.

## Query parameters

- `nodeId` string
- `page` integer
- `limit` integer
- `depth` integer
- `nodeTypes` string[]
- `createdAfter` string: A date filter of `GET /connectors/navigate`: `YYYY-MM-DD` (UTC; start of the day for a lower bound, end of the day for an upper bound), or a date and time with a timezone offset (`Z` or `±HH:MM`). Empty, blank or timezone-naive values are refused with `400`.
- `createdBefore` string: A date filter of `GET /connectors/navigate`: `YYYY-MM-DD` (UTC; start of the day for a lower bound, end of the day for an upper bound), or a date and time with a timezone offset (`Z` or `±HH:MM`). Empty, blank or timezone-naive values are refused with `400`.
- `modifiedAfter` string: A date filter of `GET /connectors/navigate`: `YYYY-MM-DD` (UTC; start of the day for a lower bound, end of the day for an upper bound), or a date and time with a timezone offset (`Z` or `±HH:MM`). Empty, blank or timezone-naive values are refused with `400`.
- `modifiedBefore` string: A date filter of `GET /connectors/navigate`: `YYYY-MM-DD` (UTC; start of the day for a lower bound, end of the day for an upper bound), or a date and time with a timezone offset (`Z` or `±HH:MM`). Empty, blank or timezone-naive values are refused with `400`.

## Response `200`

Successful operation. A node that does not exist or is not
accessible returns an empty view (null `current`, empty `rows`)
rather than an error.

- NavigateKnowledgeGraphResponseSchema: Response returned by GET /connectors/navigate. Field names are snake_case, matching the knowledge graph's internal view models. `text` carries the same flat-text rendering PipesHub's own agent sees for this node; the remaining fields carry the same information in structured form.
  - `current` KnowledgeGraphNodeRefSchema, required: Minimal identity reference for a node in the knowledge graph.
    - `id` string, required: Node identifier. Pass it back as `nodeId` to open this node. When `is_record` is true it is also the Record ID accepted by GET /connectors/record/{recordId}/content.
    - `name` string, required
    - `node_type` string, required: One of `app`, `recordGroup`, `folder`, `record`.
    - `sub_type` string, nullable, required: e.g. `TICKET`, `CONFLUENCE_PAGE`, `PROJECT`, `COLLECTION`.
    - `is_record` boolean, required: True for record and folder nodes — the nodes whose content can be read via GET /connectors/record/{recordId}/content.
  - `breadcrumbs` KnowledgeGraphNodeRefSchema[], required: Root to parent, not including `current`.
    - `id` string, required: Node identifier. Pass it back as `nodeId` to open this node. When `is_record` is true it is also the Record ID accepted by GET /connectors/record/{recordId}/content.
    - `name` string, required
    - `node_type` string, required: One of `app`, `recordGroup`, `folder`, `record`.
    - `sub_type` string, nullable, required: e.g. `TICKET`, `CONFLUENCE_PAGE`, `PROJECT`, `COLLECTION`.
    - `is_record` boolean, required: True for record and folder nodes — the nodes whose content can be read via GET /connectors/record/{recordId}/content.
  - `rows` KnowledgeGraphNodeRowSchema[], required: The current node's children for this page. With `depth` > 1 this is a flat list of all descendants up to that depth, each row carrying its own `level`.
    - `id` string, required
    - `name` string, required
    - `node_type` string, required: One of `recordGroup`, `folder`, `record`, or `app`. A listing holds `app` nodes only at the root of a connected app whose limit names spaces, folders or files as well as whole sources: there it lists those sources.
    - `sub_type` string, nullable, required
    - `is_record` boolean, required
    - `has_children` boolean, required: Whether this node can itself be opened with `nodeId`.
    - `detail` string, nullable, required: e.g. size, indexing status, or relationship type.
    - `web_url` string, nullable: Link to the record in its source system. Records that carry a relative URL (uploaded/KB records) are resolved against the configured frontend public URL (see POST /configurationManager/frontendPublicUrl). The value is null when that host is not configured.
    - `indexing_status` string, nullable
    - `source_created_at` integer, nullable: Creation time in the source system, epoch milliseconds. Null when the underlying node did not carry one.
    - `source_modified_at` integer, nullable
    - `level` integer: 1-based nesting depth from the navigated parent. Always 1 for a `depth=1` listing; 2 or 3 for deeper rows when `depth` > 1.
    - `context_summary` string, nullable
  - `related` KnowledgeGraphNodeRowSchema[], required: Cross-referenced records (non-containment edges), e.g. the Confluence page linked from a Jira ticket. Page 1 only.
    - `id` string, required
    - `name` string, required
    - `node_type` string, required: One of `recordGroup`, `folder`, `record`, or `app`. A listing holds `app` nodes only at the root of a connected app whose limit names spaces, folders or files as well as whole sources: there it lists those sources.
    - `sub_type` string, nullable, required
    - `is_record` boolean, required
    - `has_children` boolean, required: Whether this node can itself be opened with `nodeId`.
    - `detail` string, nullable, required: e.g. size, indexing status, or relationship type.
    - `web_url` string, nullable: Link to the record in its source system. Records that carry a relative URL (uploaded/KB records) are resolved against the configured frontend public URL (see POST /configurationManager/frontendPublicUrl). The value is null when that host is not configured.
    - `indexing_status` string, nullable
    - `source_created_at` integer, nullable: Creation time in the source system, epoch milliseconds. Null when the underlying node did not carry one.
    - `source_modified_at` integer, nullable
    - `level` integer: 1-based nesting depth from the navigated parent. Always 1 for a `depth=1` listing; 2 or 3 for deeper rows when `depth` > 1.
    - `context_summary` string, nullable
  - `pagination` KnowledgeGraphPaginationSchema, required: Pagination envelope for a navigate listing.
    - `page` integer, required
    - `limit` integer, required
    - `total` integer, required: Total children of the current node, ignoring pagination.
    - `has_next` boolean, required
    - `has_prev` boolean, required
  - `web_url` string, nullable, required
  - `indexing_status` string, nullable, required
  - `connector` string, nullable, required
  - `context_block` string, nullable: Type-specific metadata for the current node when it is a record — for a ticket, status, assignee, priority and dates.
  - `text` string, required: Flat-text rendering of this view: breadcrumbs, the current node's metadata, the children listing with an id per row, `Related:`, and a closing `Next:` line naming a follow-up call. Shape depends on the page: pages after the first omit the header, breadcrumbs and related rows to stay compact, while the structured fields above remain complete. Capped at 25,000 bytes, with a truncation marker appended when exceeded.

## Other responses

- `400`: A parameter failed validation. Refused by the gateway (`VALIDATION_ERROR`): `page` below 1, `limit` outside 50-200, `depth` outside 1-3, an empty or blank `nodeId` or date, a parameter other than `nodeTypes` sent more than once. Refused by the connector service (`HTTP_BAD_REQUEST`): a date that is not ISO 8601, carries no timezone offset, is not a calendar date, forms an inverted range, or has `createdAfter` in the future. Also returned, before authentication, when a query value, or any string in a JSON or form-encoded body, looks like markup to the app-wide XSS filter: an HTML tag, a script tag, `<iframe`, `<object`, `<embed` or `<svg` tag, a word starting with `on` followed by `=` (meant for inline event handlers such as `onerror=`, it also catches plain text such as `one=1`), a `javascript:` or `data:text/html` URL, an encoded script tag (`&lt;script`, `%3cscript`), or any string longer than 100,000 characters (`HTTP_BAD_REQUEST`, "HTML tags, scripts, and XSS content are not allowed in ...", naming the field or query parameter; a string over 100,000 characters is refused as too long instead). A JSON body that does not parse is refused the same way, also before authentication (`HTTP_BAD_REQUEST`, "The request body is not valid JSON.").
- `401`: Missing, invalid, expired, or revoked authentication
- `403`: OAuth token is missing both the `kb:read` and `connector:read` scopes.
- `404`: The authenticated user could not be resolved
- `500`: Internal server error while navigating the knowledge graph. A JSON body larger than 10 MB, or a form-encoded body larger than 100 KB or with more than 1000 fields, is answered `413` by the app-wide body parsers instead, also before authentication.
- `503`: Connector service unavailable or connection refused

## Changes

- **2026-10-28** `dbb5e203b445`: 5 breaking, 2 info
  - added the pattern `\S` to the `query` request parameter `nodeId`
  - added the pattern `^\d{4}-\d{2}-\d{2}([T ]\d{2}(:\d{2}(:\d{2}([.,]\d+)?)?)?([Zz]|[+-]\d{2}(:?\d{2})?))?$` to the `query` request parameter `createdAfter`
  - added the pattern `^\d{4}-\d{2}-\d{2}([T ]\d{2}(:\d{2}(:\d{2}([.,]\d+)?)?)?([Zz]|[+-]\d{2}(:?\d{2})?))?$` to the `query` request parameter `createdBefore`
  - added the pattern `^\d{4}-\d{2}-\d{2}([T ]\d{2}(:\d{2}(:\d{2}([.,]\d+)?)?)?([Zz]|[+-]\d{2}(:?\d{2})?))?$` to the `query` request parameter `modifiedAfter`
  - …3 more
- **2026-10-08** `bb0c59adf026`: 6 info
  - added the optional property `error/requestId` to the response with the `400` status
  - added the optional property `error/requestId` to the response with the `401` status
  - added the optional property `error/requestId` to the response with the `403` status
  - added the optional property `error/requestId` to the response with the `404` status
  - …2 more
- **2026-08-12** `11f5086fcbb8`: 2 info
  - the security scope `connector:read` was added to the endpoint's security scheme `oauth2`
  - the security scope `kb:read` was removed from the endpoint's security scheme `oauth2`
- **2026-08-12** `5798f431973a`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api/changes/connectors/navigate/get.md)

---

[API](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api.md) - [All operations](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api/llms.txt) - [OpenAPI document](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api/revisions/dbb5e203b445?raw)
