---
title: "Delivery links API reference"
canonical_url: https://zentrik.ai/docs/api/delivery-links
markdown_url: https://zentrik.ai/docs/api/delivery-links.md
last_reviewed: 2026-11-07
---

# Delivery links API reference

Read and correct which GitHub pull requests deliver an idea or initiative. Request ideas:read or initiatives:read to read, and ideas:write or initiatives:write to change links for that kind of record. A PR claims completion only through a Zentrik: closes trailer.

- Human reference: https://zentrik.ai/docs/api/delivery-links
- Complete Markdown index: https://zentrik.ai/docs/api/index.md
- Base URL: `https://zentrik.ai/api`
- Authentication: `Authorization: Bearer YOUR_API_KEY`
- Shared pagination and rate limits: https://zentrik.ai/docs/api/index.md#shared-conventions

## GET /external/v1/delivery-links — List delivery links

Operation ID: `list-delivery-links`

List the pull requests linked to one idea or initiative (record), or the ideas and initiatives linked to one pull request (url, or repository and number). Each link has status (linked counts as delivery; suggested, rejected and withdrawn are kept for their history), intent (closes when the PR claims it completes the record), source (trailer, branch or manual) and declaredBy, where the PR names the record today. Links to an initiative's promoted ideas are listed on those ideas. A pull request lookup also returns declaredReferences and only the record kinds the key can read.

Required API key scopes: `ideas:read`, `initiatives:read`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `record` | string | No | IDEA-n or INITIATIVE-n. Give this or a pull request. Needs ideas:read or initiatives:read for that kind. |
| `url` | url | No | Pull request URL. Give this, or number, instead of record. |
| `number` | integer | No | Pull request number. |
| `repository` | string | No | owner/repository, needed with number when several tracked repositories have it. |
| `includeInactive` | boolean | No | true adds rejected and withdrawn links. Read them before re-linking a pair. |

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | record or pullRequest, and items. | — |
| 400 | Invalid request | Unsupported field, a record that is not IDEA-n or INITIATIVE-n, both or neither of url and number, or a number several tracked repositories share. | — |
| 403 | Missing scope | The key lacks ideas:write for an idea or initiatives:write for an initiative. | — |
| 404 | Not found | The record is not in this workspace, or the pull request has not been synced from a repository the workspace tracks. | — |

### Example response

```json
{
  "record": {
    "type": "idea",
    "publicId": "IDEA-42",
    "name": "Selective import",
    "status": "Approved"
  },
  "items": [
    {
      "id": "33333333-3333-4333-8333-333333333333",
      "record": {
        "type": "idea",
        "publicId": "IDEA-42",
        "name": "Selective import",
        "status": "Approved"
      },
      "pullRequest": {
        "repository": "example/app",
        "number": 42,
        "title": "Import only the selected sources",
        "state": "merged",
        "url": "https://github.com/example/app/pull/42",
        "mergedAt": "2026-09-10T10:00:00.000Z"
      },
      "status": "linked",
      "intent": "relates",
      "source": "manual",
      "declaredBy": null,
      "reviewedAt": "2026-09-10T10:00:00.000Z"
    }
  ]
}
```

---

## POST /external/v1/delivery-links — Link a PR to a record

Operation ID: `create-delivery-link`

Link a pull request to an idea or initiative it works on, as related work, the same as linking it in the app. Repeating the call returns changed:false. It never claims the PR completes the record: only a Zentrik: closes IDEA-n line in the PR body does that, and note returns the line to add. Linking a pair someone rejected restores it.

Required API key scopes: `ideas:write`, `initiatives:write`

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `record` | string | Yes | IDEA-n or INITIATIVE-n. |
| `pullRequest.url` | url | No | https://github.com/owner/repository/pull/number. Give this or pullRequest.number. |
| `pullRequest.number` | integer | No | Pull request number. Give this or pullRequest.url. |
| `pullRequest.repository` | string | No | owner/repository. Needed with number when more than one tracked repository has that number. |

### Example request

```json
{
  "record": "IDEA-42",
  "pullRequest": { "url": "https://github.com/example/app/pull/42" }
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | changed says whether anything was saved; item is the link as it now stands. | — |
| 400 | Invalid request | Unsupported field, a record that is not IDEA-n or INITIATIVE-n, both or neither of url and number, or a number several tracked repositories share. | — |
| 403 | Missing scope | The key lacks ideas:write for an idea or initiatives:write for an initiative. | — |
| 404 | Not found | The record is not in this workspace, or the pull request has not been synced from a repository the workspace tracks. | — |

### Example response

```json
{
  "changed": true,
  "item": {
    "id": "33333333-3333-4333-8333-333333333333",
    "record": {
      "type": "idea",
      "publicId": "IDEA-42",
      "name": "Selective import",
      "status": "Approved"
    },
    "pullRequest": {
      "repository": "example/app",
      "number": 42,
      "title": "Import only the selected sources",
      "state": "merged",
      "url": "https://github.com/example/app/pull/42",
      "mergedAt": "2026-09-10T10:00:00.000Z"
    },
    "status": "linked",
    "intent": "relates",
    "source": "manual",
    "declaredBy": null,
    "reviewedAt": "2026-09-10T10:00:00.000Z"
  },
  "note": "Linked as related work. To claim this PR completes IDEA-42, add \"Zentrik: closes IDEA-42\" to its body; Zentrik reads completion only from the PR."
}
```

---

## POST /external/v1/delivery-links/unlink — Reject a delivery link

Operation ID: `unlink-delivery-link`

Reject a wrong link between a pull request and an idea or initiative. The rejection is remembered, so the pair is not linked again from the same PR text. When the PR still names the record, followUp says which line to change. A link whose trailer the PR has already dropped is withdrawn instead (status withdrawn), so it returns if the reference comes back. Does not change the record's status or a recorded shipment.

Required API key scopes: `ideas:write`, `initiatives:write`

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `record` | string | Yes | IDEA-n or INITIATIVE-n. |
| `pullRequest.url` | url | No | https://github.com/owner/repository/pull/number. Give this or pullRequest.number. |
| `pullRequest.number` | integer | No | Pull request number. Give this or pullRequest.url. |
| `pullRequest.repository` | string | No | owner/repository. Needed with number when more than one tracked repository has that number. |

### Example request

```json
{
  "record": "IDEA-42",
  "pullRequest": { "repository": "example/app", "number": 42 }
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | changed says whether anything was saved; item is the link as it now stands. | — |
| 400 | Invalid request | Unsupported field, a record that is not IDEA-n or INITIATIVE-n, both or neither of url and number, or a number several tracked repositories share. | — |
| 403 | Missing scope | The key lacks ideas:write for an idea or initiatives:write for an initiative. | — |
| 404 | Not found | The record is not in this workspace, or the pull request has not been synced from a repository the workspace tracks. | — |

### Example response

```json
{
  "changed": true,
  "item": {
    "id": "33333333-3333-4333-8333-333333333333",
    "record": {
      "type": "idea",
      "publicId": "IDEA-42",
      "name": "Selective import",
      "status": "Approved"
    },
    "pullRequest": {
      "repository": "example/app",
      "number": 42,
      "title": "Import only the selected sources",
      "state": "merged",
      "url": "https://github.com/example/app/pull/42",
      "mergedAt": "2026-09-10T10:00:00.000Z"
    },
    "status": "rejected",
    "intent": "relates",
    "source": "trailer",
    "declaredBy": {
      "in": "trailer",
      "intent": "relates"
    },
    "reviewedAt": "2026-09-10T10:00:00.000Z"
  },
  "followUp": "The PR body still has a Zentrik: line naming IDEA-42. The link stays rejected, but remove IDEA-42 from that line so the PR and Zentrik agree."
}
```
