# GET /api/v2/work-items/{work_item}/links

List a work item's links

- MCP id: work-items.links.index
- Scope: api:read:project_management
- Permission: project_management::view_backlog
- Rate cost: 1 unit, read bucket. `view=detail` makes it 3. Adds: each include +1.
- Cache-Control: private, no-store

Returns every link touching one work item, in both directions: the links it is the source of and the links it is the target of, which is what the linked items section in plnnrly shows.

`direction` and `relationship` on each row are relative to the work item in the path, so the same link reads `forward` / `blocks` here and `inverse` / `is blocked by` from the other end. The path accepts a numeric id or an issue key, so `work-items/ACM-123/links` works. There is no organisation-wide collection of links and no `filter[source_work_item_id]` or `filter[target_work_item_id]`: the path supplies both. Ordered by id ascending, and `meta.page.total` is always present; `?with_total` is a `400`. Listing additionally requires `project_management::manage_work_items` on the work item.

## Parameters
- work_item (integer or string, path): The WorkItem's numeric id. Or its issue_key, matching `[A-Z][A-Z0-9]*-[0-9]+`.
- view (string, optional): Which field set to render.
- per_page (integer 1 to 100, optional): Rows per page. At most 25 when `include` names a to-many relation; a larger value is 400 invalid-query-parameter.
- cursor (string, optional): Opaque keyset cursor from a previous page's links.next. Never construct one by hand.
- page (integer 1 to 1000, optional): Opt in to page-number paging: 1-based, at most 1000. Omit it, the default, to page by opaque cursor, which is what links.next hands you. Cannot be combined with cursor. Published only on collections that count their rows on every request.
- filter[created_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): Creation timestamp. Pair with `sort=id` for a stable full export. Operators: = gte lt.
- filter[created_by] (integer, optional): User who created the link. `[null]` selects links whose creator has since been deleted. Operators: = in null.
- filter[link_type] (string, optional): Relationship type: `blocks`, `clones`, `duplicates`, `merged_into`, `causes`, `relates_to` or `split_to`. The value is stored from the source item's point of view, so it does not flip on an inverse link: filter on `blocks` and you get both the items this one blocks and the items that block it. Operators: = ne in.
- filter[updated_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): Last-write timestamp. Use for incremental sync. Operators: = gte lt.
- sort (string, optional): Up to three keys, comma-separated, each optionally prefixed with `-` for descending.
- include (string, optional): Comma-separated names to inline, at most five.
- X-Request-Id (header, optional): A correlation id of your own. It is recorded in our logs next to the server's request id but never returned: the response header always carries the server's id. A value that does not match the pattern is discarded silently, never rejected.
- If-None-Match (header, optional): The ETag a read is conditional on. A match is answered 304 with no body.

## Response 200
- id (integer, required): Unique identifier.
- source_work_item_id (integer, required): Work item the link points away from. On a link created through `POST work-items/{work_item}/links` this is always the work item named in the path.
- target_work_item_id (integer, required): Work item the link points at. Always in the same project as the source.
- link_type (string, required): The relationship, stored from the source item's point of view: `blocks`, `clones`, `duplicates`, `merged_into`, `causes`, `relates_to` or `split_to`. Only `relates_to` is symmetric.
- created_by (integer or null, required, server-assigned): User who created the link, or `null` where that account has since been deleted. Resolve it with `GET /api/v2/users/{user}`; it is not includable.
- created_at (timestamp (YYYY-MM-DDThh:mm:ssZ), required): Creation timestamp.
- updated_at (timestamp (YYYY-MM-DDThh:mm:ssZ), required): Last-write timestamp; use for incremental sync.
- direction (string, required): Which way this link points relative to the work item you asked about: `forward` when that item is the source, `inverse` when it is the target. On the flat `GET work-item-links/{work_item_link}` there is no work item in the path, so the link is read on its own terms and this is always `forward`.
- relationship (string, required): The relationship in words, from the point of view of the work item you asked about: `blocks` from the source end, `is blocked by` from the target end. Always in English: the API pins the locale.
- source_work_item (Ref or WorkItemSummary, required): Work item the link points away from.
- target_work_item (Ref or WorkItemSummary, required): Work item the link points at.
- links (WorkItemLinkLinks, required)
  - self (url, required): The canonical URI of this record.

## Errors
- 403 forbidden-by-policy | insufficient-permission | insufficient-token-scope: Forbidden.
- 304 : Not modified.
- 400 idempotency-key-required | invalid-cursor | invalid-query-parameter | malformed-request | unsupported-parameter: Bad request.
- 401 token-expired | unauthenticated: Unauthenticated.
- 404 endpoint-not-found | resource-not-found: Not found.
- 406 not-acceptable: Not acceptable.
- 429 rate-limit-exceeded: Too many requests.
- 500 internal-error: Server error.
- 503 tenant-unavailable: Service unavailable.

## Example
```bash
curl -G \
  'https://<your-url>/api/v2/work-items/1/links' \
  --data-urlencode 'filter[link_type]=blocks' \
  --data-urlencode 'include=source_work_item,target_work_item' \
  -H 'Authorization: Bearer <token>' \
  -H 'Accept: application/json'
```
