> For the complete documentation index, see [llms.txt](https://sandgarden.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sandgarden.gitbook.io/docs/api.md).

# API

Doc Holiday's API allows for easy integration into any release pipeline!

You can:

* Ask Doc Holiday to create release notes and/or documentation updates for one or more publications.
* Poll a job to track its state: requested → running → done, cancelled, or errored.
* List jobs to review recent activity.

### Authentication

Doc Holiday uses the standard HTTP Authorization header along with API keys to authenticate. Every call to the Doc Holiday API requires authentication.

```shell
curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" 
  ...
```

#### Creating an API key

1. In the UI, open the Settings page → [API Keys](https://app.doc.holiday/settings/api-keys).
2. Click Add API Key.
3. Enter a Name and optional Expires At value.
4. Create the key, then copy the token shown on creation and store it in your secret manager. The token cannot be retrieved later within the UI.

### Users API

The Users API exposes authenticated user records.

#### Get the current user

Endpoint: GET /api/v1/me

Return the authenticated user record. This endpoint returns the `GetUserResponse` shape.

Response fields:

* `id`
* `authId`
* `email`
* `name`
* `sfsToken`
* `invitationAccepted`
* `orgId`
* `createdAt`
* `updatedAt`

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/me
```

#### List users

Endpoint: GET /api/v1/users

Return user records within the organization.

Query parameters:

* **email** (optional)
* **name** (optional)
* **authId** (optional)
* **query** (optional): search text for matching users
* **roleIds** (optional): comma-separated role IDs to include
* **noBuiltinRole** (optional boolean): exclude builtin role memberships
* **invitationAccepted** (optional boolean): filter by invitation acceptance
* **next** (optional): pagination cursor
* **pageSize** (optional): items per page

When clients send `roleIds`, they use a comma-separated list.

Response:

* Returns user records for the organization.
* The response uses `users` as the list key.
* List results sort alphabetically by display name and fall back to email when the display name is missing.
* The response includes `nextPageToken` and `previousPageToken`.

Example Response:

```json
{
  "users": [
    {
      "id": "usr-01hzy6abc123def456ghi789j",
      "authId": "user_2abcDEFghiJKL",
      "email": "alex@example.com",
      "name": "Alex Example",
      "orgId": "org-49440c77dc13f38d",
      "createdAt": "2026-03-30T14:28:03Z",
      "updatedAt": "2026-03-30T14:28:03Z"
    }
  ],
  "nextPageToken": "..."
}
```

The list endpoint resumes with `next` and returns the next cursor in `nextPageToken`.

#### Get a user

Endpoint: GET /api/v1/users/{id}

Return the matching user record.

Path parameters:

* **id** (required) user ID

Response:

* Returns the matching user record.
* The response includes role assignments when the user has them.

Example Response:

```json
{
  "id": "usr-01hzy6abc123def456ghi789j",
  "authId": "user_2abcDEFghiJKL",
  "email": "alex@example.com",
  "name": "Alex Example",
  "orgId": "org-49440c77dc13f38d",
  "createdAt": "2026-03-30T14:28:03Z",
  "updatedAt": "2026-03-30T14:28:03Z",
  "roles": [
    {
      "id": "rol-01hzy7orglevel123456789",
      "orgId": "org-49440c77dc13f38d",
      "name": "Organization admin",
      "builtin": true,
      "orgLevel": true,
      "createdAt": "2026-03-30T14:28:03Z",
      "updatedAt": "2026-03-30T14:28:03Z"
    }
  ]
}
```

#### Upsert a user

Endpoint: POST /api/v1/users/upsert

Create or update a user and optionally assign a role.

Request:

* **email** user email address
* **name** display name
* **authId** external auth identifier
* **roleId** optional initial role ID

Example Request Body:

```json
{
  "email": "alex@example.com",
  "name": "Alex Example",
  "authId": "user_2abcDEFghiJKL",
  "roleId": "rol-01hzy7orglevel123456789"
}
```

Response:

* Returns `201 Created`.
* Returns the created or updated user record.

Example Response:

```json
{
  "id": "usr-01hzy6abc123def456ghi789j",
  "authId": "user_2abcDEFghiJKL",
  "email": "alex@example.com",
  "name": "Alex Example",
  "orgId": "org-49440c77dc13f38d",
  "createdAt": "2026-03-30T14:28:03Z",
  "updatedAt": "2026-03-30T14:28:03Z",
  "roles": [
    {
      "id": "rol-01hzy7orglevel123456789",
      "orgId": "org-49440c77dc13f38d",
      "name": "Organization admin",
      "builtin": true,
      "orgLevel": true,
      "createdAt": "2026-03-30T14:28:03Z",
      "updatedAt": "2026-03-30T14:28:03Z"
    }
  ]
}
```

#### Delete a user

Endpoint: DELETE /api/v1/users/{id}

Remove the user record and related role assignments.

Path parameters:

* **id** (required) user ID

Response:

* Returns `204 No Content`.
* Removes the user record and related role assignments.

#### Delete an organization membership

Endpoint: DELETE /api/org-memberships?userId=...

Remove the organization membership before the user deletion flow runs.

Query parameters:

* **userId** (required) user ID

Response:

* Missing `userId` returns `400 Bad Request`.

### Conversations API

The Conversations API lists conversation records. Inaccessible conversations based upon the caller's permission level will not appear in the response.

#### List conversations

Endpoint: GET /api/v1/conversations

Query parameters:

* **branch** (optional)
* **outputUrl** (optional)
* **jobId** (optional)
* **publicationId** (optional)
* **operationType** (optional)
* **status** (optional)
* **summary** (optional)
* **staged** (optional boolean)
* **originType** (optional)
* **originURL** (optional)
* **token** (optional): encoded pagination token
* **next** (optional): pagination cursor
* **orderBy** (optional): server-supported sort column
* **pageSize** (optional): items per page
* **ascending** (optional boolean): sort direction

Response:

* Returns a list keyed by `conversations`.
* Returns `nextPageToken` and `previousPageToken`.

Example Response:

```json
{
  "conversations": [
    {
      "id": "cnv-...",
      "status": "running",
      "publicationName": "My Publication"
    }
  ],
  "nextPageToken": "..."
}
```

#### Create a conversation

Endpoint: POST /api/v1/conversations

Create a new conversation record.

Request:

* **body** (required): conversation text
* **relevantLinks** (optional): supporting links
* **changes** (optional): explicit change ranges
* **stage** (optional boolean): stages the conversation so the work is prepared without opening a pull request or merge request immediately
* **publication** (optional): publication for the conversation
* **labels** (optional): labels for the conversation

Response:

* Returns `200 OK`.
* Returns the created conversation record.
* The response uses the same conversation object returned by `GET /api/v1/conversations/{id}`.

Example Request Body:

```json
{
  "body": "Please draft release notes for the latest product updates.",
  "relevantLinks": [
    "https://github.com/example/repo/pull/123"
  ],
  "changes": [
    {
      "commits": {
        "endSha": "abc123"
      }
    }
  ],
  "stage": true,
  "publication": "pub-01hzy4p1v2w3x4y5z6a7b8c9d",
  "labels": [
    "release-notes",
    "staged"
  ]
}
```

Example Response:

```json
{
  "id": "cnv-01hzyab1c2d3e4f5g6h7j8k9m",
  "status": "running",
  "summary": "Please draft release notes for the latest product updates.",
  "publicationName": "Product docs writer",
  "staged": true,
  "publicationId": "pub-01hzy4p1v2w3x4y5z6a7b8c9d",
  "createdAt": "2026-03-31T12:34:56Z",
  "updatedAt": "2026-03-31T12:34:56Z"
}
```

cURL Example:

```shell
curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
        "body": "Please draft release notes for the latest product updates.",
        "relevantLinks": ["https://github.com/example/repo/pull/123"],
        "changes": [{
          "commits": {
            "endSha": "abc123"
          }
        }],
        "stage": true,
        "publication": "pub-01hzy4p1v2w3x4y5z6a7b8c9d",
        "labels": ["release-notes", "staged"]
      }' \
  https://api.doc.holiday/api/v1/conversations
```

#### Create a conversation comment

Endpoint: POST /api/v1/conversations/{id}/comments

Create a conversation comment on an existing conversation.

Request:

* `body` (required): comment text
* `relevantLinks` (optional): supporting links
* `changes` (optional): explicit change ranges
* `labels` (optional): labels for the comment
* `anchor` (optional): file-anchored metadata
* `workRequested` (optional): marks the comment as a work request

The same endpoint handles both discussion-only comments and work request comments. Discussion-only comments require the `discussion-comment` permission. Work request comments require "create" permissions.

Response:

* Returns the created comment object for discussion-only comments.
* Work-requested comments run asynchronously and may not return a created comment in the response.

Response fields:

* `id`
* `conversationId`
* `connectionId`
* `automationId`
* `authorName`
* `userId`
* `message`
* `processingTime`
* `position`
* `userType`
* `createdAt`
* `updatedAt`
* `anchor`
* `workRequested`
* `source`
* `externalId`
* `externalUrl`
* `batchItemIds`
* `batchedIntoIds`
* `inReplyToId`
* `replyIds`

#### List conversation comments

Endpoint: GET /api/v1/conversation\_comments

Return a paginated list of comments.

Query parameters:

* `ids` (optional): comment IDs
* `conversationId` (optional): conversation ID filter
* `connectionId` (optional): connection ID filter
* `workRequested` (optional): work-request filter
* `source` (optional): comment source
* `externalId` (optional): external comment ID
* `filePath` (optional): anchored file path

The list will only include comments attached to conversations based upon the caller's permission level.

#### Mutation note

Only the author can update or delete a comment. The API does not allow updates or deletes for work-requested or batched comments.

#### Update a conversation comment

Endpoint: PATCH /api/v1/conversation\_comments/{id}

Update the comment message.

Request:

* `message` (required): updated comment text

Response:

* Returns `200 OK` with the updated comment object.

#### Delete a conversation comment

Endpoint: DELETE /api/v1/conversation\_comments/{id}

Remove the comment.

Response:

* Returns `204 No Content`.

#### List diffs for a conversation

Endpoint: GET /api/v1/conversations/{id}/diffs

* Auth: Authorization: Bearer

Sample 200 response:

```json
{
  "diffs": [
    {
      "filename": "docs/api.md",
      "additions": 10,
      "deletions": 2,
      "changes": 12,
      "status": "modified",
      "patch": "@@ ..."
    }
  ],
  "error": null
}
```

### Work History API

The Work History API exposes conversation turns and retry operations.

#### List conversation turns

Endpoint: GET /api/v1/conversation\_turns

Return a paginated list of conversation turns.

Query parameters:

* **conversationId** (optional): conversation ID filter
* **status** (optional): turn status filter
* **createdAfter** (optional): return turns created after this timestamp
* **retryMaxCount** (optional): maximum retry count to include
* **token** (optional): encoded pagination token
* **next** (optional): pagination cursor
* **orderBy** (optional): server-supported sort column
* **pageSize** (optional): items per page
* **ascending** (optional boolean): sort direction

The `conversationId` filter narrows the list to one conversation. The `retryMaxCount` filter narrows the list to turns that stay within the requested retry limit.

Response:

* Returns a paginated list of conversation turns.
* Each turn uses the `GetConversationTurnResponse` shape with `id`, `orgId`, `plan`, `status`, `request`, `summary`, `createdAt`, and `updatedAt`.

Example Response:

```json
{
  "conversationTurns": [
    {
      "id": "ctn-01hzy9abc123def456ghi789j",
      "orgId": "org-49440c77dc13f38d",
      "plan": {
        "planned": true,
        "encodedRequests": []
      },
      "status": "running",
      "request": {
        "manualRequest": {
          "title": "Update docs"
        }
      },
      "summary": "Working through documentation updates.",
      "createdAt": "2026-03-31T12:34:56Z",
      "updatedAt": "2026-03-31T12:35:12Z"
    }
  ],
  "nextPageToken": "..."
}
```

#### Get a conversation turn

Endpoint: GET /api/v1/conversation\_turns/{id}

Path parameters:

* **id** (required): conversation turn ID

Response:

* Returns the matching conversation turn.
* The response uses the `GetConversationTurnResponse` shape with `id`, `orgId`, `plan`, `status`, `request`, `summary`, `createdAt`, and `updatedAt`.

Example Response:

```json
{
  "id": "ctn-01hzy9abc123def456ghi789j",
  "orgId": "org-49440c77dc13f38d",
  "plan": {
    "planned": true,
    "encodedRequests": []
  },
  "status": "done",
  "request": {
    "manualRequest": {
      "title": "Update docs"
    }
  },
  "summary": "Completed documentation updates.",
  "createdAt": "2026-03-31T12:34:56Z",
  "updatedAt": "2026-03-31T12:35:12Z"
}
```

#### Update a conversation

Endpoint: PUT /api/v1/conversations/{id}

* Auth: Authorization: Bearer

Request:

* **excludedFiles** (optional string\[])
* **prTitle** (optional string)

cURL Example:

```shell
curl -X PUT \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "excludedFiles": ["docs/internal-notes.md"]
  }' \
  'https://api.doc.holiday/api/v1/conversations/cnv-123'
```

Returns `200` with a conversation object.

### Connections API

The Connections API creates and manages connections.

The server redacts secret values in connection configuration responses. It omits `signingSecret` and `externalWebhookId` from response bodies.

#### Create a connection

Endpoint: POST /api/v1/connections

Create a connection record. The request body uses a provider-specific `config` object.

Request:

* **name** (required) string
* **config** (required) object. In practice, this is where the provider-specific connection settings are supplied
* **sync** (optional) boolean; when set, triggers a sync after creation.
* **paused** (optional) boolean; when set, pauses background sync jobs for the connection.

Provider-specific `config`:

Populate exactly one provider configuration from the following within a given request:

* **documentation**: `url`, optional `username` and `password` for basic authentication
  * The `url` value must be a valid absolute URL with both scheme and host. The API rejects malformed URLs and scheme-less URLs when creating or updating a documentation connection.
* **githubApp**: `installationId`
* **githubRepo**: `githubAppConnectionId`, `repositoryUrl`, optional `mainBranch`
  * `mainBranch` will default to `main` if not specified.
  * `githubAppConnectionId` must be the doc holiday ID of a `githubApp` connection.
* **githubAccessToken**: `accessToken`, `repositoryUrl`, optional `mainBranch`
* **notion**: `integrationKey`
* **gcp**: `serviceAccountJSON`
* **aws**: `accessKeyID`, `secretAccessKey`, `region`
* **linear**: `apiKey`
* **gitlab**: `projectId`, `accessToken`, optional `mainBranch`
* **gitlabProvider**: `accessToken`
* **gitlabProject**: `gitlabProviderConnectionId`, `projectId`, optional `mainBranch`
* `gitlabProviderConnectionId` must be the doc holiday ID of a `gitlabProvider` connection.
* **bitbucketRepo**: `workspace`, `repoSlug`, `accessToken`, optional `mainBranch`
* **bitbucketProvider**: `workspace`, `accessToken`
* **bitbucketProject**: `bitbucketProviderConnectionId`, `repoSlug`, optional `mainBranch`
  * `bitbucketProviderConnectionId` must be the doc holiday ID of a `bitbucketProvider` connection.
* **confluence**: `username`, `apiToken`, `url`
* **jiraProject**: `username`, `apiToken`, `url`, `project`
* **azureBlob**: `accountName`, `accountKey`, `containerName`
* **zendesk**: `url`, `email`, `apiKey`

The following types cannot be functionally created but can be listed:

* **githubApp**: `installationId`
  * These must be created via an authentication handshake with github, starting from <https://app.doc.holiday>.

Note: Secret-bearing fields such as tokens, passwords, keys, and service-account JSON are sensitive credentials and should be stored securely by API clients.

Example Request Body:

```json
{
  "name": "GitHub repository via personal token",
  "config": {
    "githubAccessToken": {
      "accessToken": "example-access-token",
      "repositoryUrl": "owner/example-repo",
      "mainBranch": "main"
    }
  },
  "sync": true,
  "paused": false
}
```

Example Response:

```json
{
  "id": "cnn-01hzy4m8j2m3n4p5q6r7s8t9u",
  "orgId": "org-49440c77dc13f38d",
  "name": "GitHub repository via personal token",
  "type": "githubAccessToken",
  "config": {
    "githubAccessToken": {
      "accessToken": "********",
      "repositoryUrl": "owner/example-repo",
      "mainBranch": "main"
    }
  },
  "healthy": true,
  "paused": false,
  "createdAt": "2026-03-30T14:22:11Z",
  "updatedAt": "2026-03-30T14:22:11Z",
  "deletedAt": null
}
```

cURL Example:

```shell
curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "GitHub repository via personal token",
        "config": {
          "githubAccessToken": {
            "accessToken": "example-access-token",
            "repositoryUrl": "owner/example-repo",
            "mainBranch": "main"
          }
        },
        "sync": true,
        "paused": false
      }' \
  https://api.doc.holiday/api/v1/connections
```

#### List connections

Endpoint: GET /api/v1/connections

Return a list of connection records for the authenticated user's organization.

Response:

* Returns a list of connection records

Example Response:

```json
{
  "connections": [
    {
      "id": "cnn-01hzy4m8j2m3n4p5q6r7s8t9u",
      "orgId": "org-49440c77dc13f38d",
      "name": "GitHub repository via personal token",
      "type": "githubAccessToken",
      "config": {
        "githubAccessToken": {
          "accessToken": "********",
          "repositoryUrl": "owner/example-repo",
          "mainBranch": "main"
        }
      },
      "healthy": true,
      "paused": false,
      "createdAt": "2026-03-30T14:22:11Z",
      "updatedAt": "2026-03-30T14:22:11Z",
      "deletedAt": null
    }
  ]
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/connections
```

#### Get a connection

Endpoint: GET /api/v1/connections/{id}

Return the matching connection record.

Path parameters:

* **id** (required) connection ID

Response:

* Returns the requested connection record

Example Response:

```json
{
  "id": "cnn-01hzy4m8j2m3n4p5q6r7s8t9u",
  "orgId": "org-49440c77dc13f38d",
  "name": "GitHub repository via personal token",
  "type": "githubAccessToken",
  "config": {
    "githubAccessToken": {
      "accessToken": "********",
      "repositoryUrl": "owner/example-repo",
      "mainBranch": "main"
    }
  },
  "healthy": true,
  "paused": false,
  "createdAt": "2026-03-30T14:22:11Z",
  "updatedAt": "2026-03-30T14:22:11Z",
  "deletedAt": null
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/connections/cnn-01hzy4m8j2m3n4p5q6r7s8t9u
```

#### Update a connection

Endpoint: PUT /api/v1/connections/{id}

Update an existing connection record.

Path parameters:

* **id** (required) connection ID

Request:

* **name** (optional) string
* **config** (optional) object
* **paused** (optional) boolean

Example Request Body:

```json
{
  "name": "GitHub repository via personal token (updated)",
  "config": {
    "githubAccessToken": {
      "accessToken": "example-access-token",
      "repositoryUrl": "owner/example-repo",
      "mainBranch": "main"
    }
  },
  "paused": true
}
```

Example Response:

```json
{
  "id": "cnn-01hzy4m8j2m3n4p5q6r7s8t9u",
  "orgId": "org-49440c77dc13f38d",
  "name": "GitHub repository via personal token (updated)",
  "type": "githubAccessToken",
  "config": {
    "githubAccessToken": {
      "accessToken": "********",
      "repositoryUrl": "owner/example-repo",
      "mainBranch": "main"
    }
  },
  "healthy": true,
  "paused": true,
  "createdAt": "2026-03-30T14:22:11Z",
  "updatedAt": "2026-03-30T15:03:44Z",
  "deletedAt": null
}
```

cURL Example:

```shell
curl -X PUT \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "GitHub repository via personal token (updated)",
        "config": {
          "githubAccessToken": {
            "accessToken": "example-access-token",
            "repositoryUrl": "owner/example-repo",
            "mainBranch": "main"
          }
        },
        "paused": true
      }' \
  https://api.doc.holiday/api/v1/connections/cnn-01hzy4m8j2m3n4p5q6r7s8t9u
```

#### Delete a connection

Endpoint: DELETE /api/v1/connections/{id}

Remove the specified connection record.

Path parameters:

* **id** (required) connection ID

Response:

* Returns a success-oriented response when the connection is removed

Example Response:

```json
{
  "success": true
}
```

cURL Example:

```shell
curl -X DELETE \
  -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/connections/cnn-01hzy4m8j2m3n4p5q6r7s8t9u
```

#### Sync a connection

Endpoint: POST /api/v1/connections/{id}/sync

Start syncing background information for the specified connection.

Path parameters:

* **id** (required) connection ID

Response:

* Returns a success-oriented response for the sync request

Example Response:

```json
{
  "success": true
}
```

cURL Example:

```shell
curl -X POST \
  -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/connections/cnn-01hzy4m8j2m3n4p5q6r7s8t9u/sync
```

#### List GitLab projects

Endpoint: GET /api/v1/gitlab/projects

List projects available to a GitLab access token or an existing GitLab connection. Use `connectionId` in edit mode when the connection already exists; otherwise provide `token`. The list uses cursor-based pagination and returns `projects` with a `nextPageToken` value that resumes the next page.

Query parameters:

* **connectionId** (optional) GitLab connection ID. Use this in edit mode or when reloading an existing connection.
* **token** (optional when `connectionId` is set) GitLab access token. Provide it when discovering projects for a new connection.

Example Response:

```json
{
  "projects": [
    {
      "id": 123,
      "fullName": "group/example-project"
    }
  ],
  "nextPageToken": "..."
}
```

The next page resumes from the returned cursor token.

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  'https://api.doc.holiday/api/v1/gitlab/projects?connectionId=cnn-01hzy4m8j2m3n4p5q6r7s8t9u'
```

#### List Bitbucket repositories

Endpoint: GET /api/v1/bitbucket/repos

List repositories available to a Bitbucket workspace access token or an existing Bitbucket connection. Use `connectionId` in edit mode when the connection already exists; otherwise provide `workspace` and `token`. The list uses cursor-based pagination and returns `repos` with a `nextPageToken` value that resumes the next page.

Query parameters:

* **connectionId** (optional) Bitbucket connection ID. Use this in edit mode or when reloading an existing connection.
* **workspace** (optional when `connectionId` is set) Bitbucket workspace slug. Provide it with `token` when `connectionId` is not set.
* **token** (optional when `connectionId` is set) Bitbucket workspace access token. Provide it with `workspace` when `connectionId` is not set.

Example Response:

```json
{
  "repos": [
    {
      "fullName": "workspace/example-repo",
      "slug": "example-repo"
    }
  ],
  "nextPageToken": "..."
}
```

The next page resumes from the returned cursor token.

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  'https://api.doc.holiday/api/v1/bitbucket/repos?workspace=example-workspace&token=<bitbucket-workspace-token>'
```

#### Get connection health

Endpoint: GET /api/v1/connections/{id}/health

Check whether a connection is healthy and can be successfully used.

Path parameters:

* **id** (required) connection ID

Response:

* Returns whether the requested connection can be used successfully or whether there is some configuration error.

Connection health checks use the centralized transient HTTP classification. They treat persistent HTTP failures as unhealthy, including `400`, `401`, `402`, `403`, `404`, `405`, `410`, `412`, `415`, `418`, and `431`.

Example Response:

```json
{
  "status": "unhealthy",
  "message": "an error message encountered when checking the connection"
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/connections/cnn-01hzy4m8j2m3n4p5q6r7s8t9u/health
```

#### List Linear teams

Endpoint: GET /api/v1/linear/teams

List Linear teams for the connected account so the Doc Holiday UI can populate the team selector.

Query parameters:

* **connectionId** (optional) existing Linear connection ID
* **apiKey** (optional) Linear API key

Response:

* Returns a list keyed by `teams`.
* Each team includes `id` and `name`.

Example Response:

```json
{
  "teams": [
    {
      "id": "team-123",
      "name": "Docs"
    }
  ]
}
```

### Audit Logs API

The Audit Logs API lists recorded audit events.

#### List audit logs

Endpoint: GET /api/v1/audit\_logs

Return recorded audit events for the authenticated organization.

Response:

* Returns a list keyed by `auditLogs`.

Example Response:

```json
{
  "auditLogs": [
    {
      "id": "aud-01hzy4m8j2m3n4p5q6r7s8t9u",
      "action": "connection.created",
      "createdAt": "2026-03-30T14:22:11Z"
    }
  ]
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/audit_logs
```

### Publications API

The Automations API creates and manages automation records.

**NOTE** - Automations within the Doc Holiday UI have been renamed Publications. Whenever interacting with an Automation, please remember that it refers to Publications. This naming conflict will be updated in a future release.

#### Create an automation

Endpoint: POST /api/v1/automations

Create an automation record.

Request:

* **name** automation name
* **config** automation configuration object

Example Request Body:

```json
{
  "name": "Product docs writer",
  "config": {
    "writer": {
      "sourceRepos": [
        "cnn-01hzy4m8j2m3n4p5q6r7s8t9u"
      ],
      "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
      "styleGuide": {
        "prCommitInstructions": "Use concise, action-oriented commit summaries.",
        "planningInstructions": "Prefer small updates to existing docs before creating new pages."
      }
    }
  }
}
```

Example Response:

```json
{
  "id": "aut-01hzy4p1v2w3x4y5z6a7b8c9d",
  "orgId": "org-49440c77dc13f38d",
  "name": "Product docs writer",
  "config": {
    "writer": {
      "sourceRepos": [
        "cnn-01hzy4m8j2m3n4p5q6r7s8t9u"
      ],
      "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
      "styleGuide": {
        "prCommitInstructions": "Use concise, action-oriented commit summaries.",
        "planningInstructions": "Prefer small updates to existing docs before creating new pages."
      }
    }
  },
  "createdAt": "2026-03-30T14:22:11Z",
  "updatedAt": "2026-03-30T14:22:11Z"
}
```

#### List automations

Endpoint: GET /api/v1/automations

Return automation records for the authenticated organization.

Response:

* Returns a list keyed by `automations`.

Example Response:

```json
{
  "automations": [
    {
      "id": "aut-01hzy4p1v2w3x4y5z6a7b8c9d",
      "orgId": "org-49440c77dc13f38d",
      "name": "Product docs writer",
      "config": {
        "writer": {
          "sourceRepos": [
            "cnn-01hzy4m8j2m3n4p5q6r7s8t9u"
          ],
          "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
          "styleGuide": {
            "prCommitInstructions": "Use concise, action-oriented commit summaries.",
            "planningInstructions": "Prefer small updates to existing docs before creating new pages."
          }
        }
      },
      "createdAt": "2026-03-30T14:22:11Z",
      "updatedAt": "2026-03-30T14:22:11Z"
    }
  ]
}
```

#### Get an automation

Endpoint: GET /api/v1/automations/{id}

Return the matching automation record.

Path parameters:

* **id** (required) automation ID

Response:

* Returns the requested automation record.

Example Response:

```json
{
  "id": "aut-01hzy4p1v2w3x4y5z6a7b8c9d",
  "orgId": "org-49440c77dc13f38d",
  "name": "Product docs writer",
  "config": {
    "writer": {
      "sourceRepos": [
        "cnn-01hzy4m8j2m3n4p5q6r7s8t9u"
      ],
      "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
      "styleGuide": {
        "prCommitInstructions": "Use concise, action-oriented commit summaries.",
        "planningInstructions": "Prefer small updates to existing docs before creating new pages."
      }
    }
  },
  "createdAt": "2026-03-30T14:22:11Z",
  "updatedAt": "2026-03-30T14:22:11Z"
}
```

#### List members with access to a publication

Endpoint: GET /api/v1/automations/{id}/members

Return users who can access the specified publication.

Path parameters:

* **id** (required) publication ID

Query parameters:

* **query** (optional): search text for matching members
* **writeAccess** (optional boolean): filter by writer access
* **invitationAccepted** (optional boolean): filter by invitation acceptance
* **token** (optional): encoded pagination token
* **next** (optional): pagination cursor
* **orderBy** (optional): server-supported sort column
* **pageSize** (optional): number of results to return
* **ascending** (optional boolean): sort direction

Response:

* Returns the users who currently have access to the publication.
* Each user row uses the lightweight `AutomationMember` shape with `id`, `name`, `email`, and `writeAccess`.
* The caller's effective publication access determines `writeAccess`.
* The response includes `nextPageToken` and `previousPageToken`.

Example Response:

```json
{
  "members": [
    {
      "id": "usr-01hzy6abc123def456ghi789j",
      "name": "Alex Example",
      "email": "alex@example.com",
      "writeAccess": true
    },
    {
      "id": "usr-01hzy6xyz987uvw654rst321q",
      "name": "Morgan Example",
      "email": "morgan@example.com",
      "writeAccess": false
    }
  ],
  "nextPageToken": "..."
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/automations/aut-01hzy4p1v2w3x4y5z6a7b8c9d/members
```

#### Update a publication

Endpoint: PUT /api/v1/automations/{id}

Update an existing publication.

Path parameters:

* **id** (required) publication ID

Request:

* **name** (optional) publication name
* **config.writer.sourceRepos** (optional) source repositories that provide the information the publication reads
* **config.writer.docsRepo** (optional) target repository where the publication writes documentation and release notes
* **config.writer.triggerOnPullRequest** (optional boolean) starts the publication from pull requests
* **config.writer.triggerOnIssue** (optional boolean) starts the publication from new issues
* **config.writer.triggerOnComment** (optional boolean) starts the publication from issue comments
* **config.writer.triggerOnRelease** (optional boolean) starts the publication from releases
* **config.writer.writeDocumentation** (optional boolean) lets the publication draft documentation
* **config.writer.writeReleaseNotes** (optional boolean) lets the publication draft release notes
* **config.writer.writeChangelog** (optional boolean) lets the publication draft changelog entries
* **config.writer.inputTriggers** (optional) selected input triggers. The field may be absent, populated, or `null`.
  * Clearing every trigger selection keeps the publication configuration valid.
* **config.writer.styleGuide.prCommitInstructions** (optional) commit guidance the publication uses when it opens pull requests
* **config.writer.styleGuide.planningInstructions** (optional) planning guidance the publication uses when it prepares work

Example Request Body:

```json
{
  "name": "Product docs writer",
  "config": {
    "writer": {
      "sourceRepos": [
        "cnn-01hzy4m8j2m3n4p5q6r7s8t9u"
      ],
      "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
      "triggerOnPullRequest": true,
      "triggerOnIssue": true,
      "triggerOnComment": true,
      "triggerOnRelease": false,
      "writeDocumentation": true,
      "writeReleaseNotes": true,
      "writeChangelog": false,
      "styleGuide": {
        "prCommitInstructions": "Use concise, action-oriented commit summaries.",
        "planningInstructions": "Prefer small updates to existing docs before creating new pages."
      }
    }
  }
}
```

Response:

* Returns the updated publication record.
* The response includes the publication's configured sources, repository target, and publication instructions.

Example Response:

```json
{
  "id": "aut-01hzy4p1v2w3x4y5z6a7b8c9d",
  "orgId": "org-49440c77dc13f38d",
  "name": "Product docs writer",
  "config": {
    "writer": {
      "sourceRepos": [
        "cnn-01hzy4m8j2m3n4p5q6r7s8t9u"
      ],
      "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
      "triggerOnPullRequest": true,
      "triggerOnIssue": true,
      "triggerOnComment": true,
      "triggerOnRelease": false,
      "writeDocumentation": true,
      "writeReleaseNotes": true,
      "writeChangelog": false,
      "styleGuide": {
        "prCommitInstructions": "Use concise, action-oriented commit summaries.",
        "planningInstructions": "Prefer small updates to existing docs before creating new pages."
      }
    }
  },
  "createdAt": "2026-03-30T14:22:11Z",
  "updatedAt": "2026-03-30T15:03:44Z"
}
```

cURL Example:

```shell
curl -X PUT \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Product docs writer",
        "config": {
          "writer": {
            "sourceRepos": ["cnn-01hzy4m8j2m3n4p5q6r7s8t9u"],
            "docsRepo": "cnn-01hzy4n7x8y9z0a1b2c3d4e5f",
            "triggerOnPullRequest": true,
            "triggerOnIssue": true,
            "triggerOnComment": true,
            "triggerOnRelease": false,
            "writeDocumentation": true,
            "writeReleaseNotes": true,
            "writeChangelog": false,
            "styleGuide": {
              "prCommitInstructions": "Use concise, action-oriented commit summaries.",
              "planningInstructions": "Prefer small updates to existing docs before creating new pages."
            }
          }
        }
      }' \
  https://api.doc.holiday/api/v1/automations/aut-01hzy4p1v2w3x4y5z6a7b8c9d
```

#### Delete a publication

Endpoint: DELETE /api/v1/automations/{id}

Delete the specified publication.

Path parameters:

* **id** (required) publication ID

Response:

* Returns a success-oriented response when the publication is removed.

Example Response:

```json
{
  "success": true
}
```

cURL Example:

```shell
curl -X DELETE \
  -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/automations/aut-01hzy4p1v2w3x4y5z6a7b8c9d
```

#### Get publication health

Endpoint: GET /api/v1/automations/{id}/health

Check whether a publication is healthy and can be successfully used.

Path parameters:

* **id** (required) publication ID

Response:

* Returns whether the requested publication can be successfully used or whether there is a configuration error.

Example Response:

```json
{
  "status": "unhealthy",
  "message": "an error message encountered when checking the publication"
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/automations/aut-01hzy4p1v2w3x4y5z6a7b8c9d/health
```

#### List members

Endpoint: GET /api/v1/members

Return users within the authenticated organization.

Query parameters:

* **email** (optional)
* **name** (optional)
* **authId** (optional)
* **ids** (optional): member IDs
* **query** (optional): search text for matching members
* **roleIds** (optional): role IDs to include
* **noBuiltinRole** (optional boolean): exclude builtin role memberships
* **invitationAccepted** (optional boolean): filter by invitation acceptance
* **token** (optional): encoded pagination token
* **next** (optional): pagination cursor
* **orderBy** (optional): server-supported sort column
* **pageSize** (optional): items per page
* **ascending** (optional boolean): sort direction

The `authId` filter narrows the member list to the matching user auth ID.

The `ids`, `query`, `roleIds`, and `noBuiltinRole` filters make it possible to narrow the member list by identity, search text, or role membership. When `token` is set to a `nextPageToken` value from an earlier response, the endpoint returns the next page of results.

Response:

* Returns member records for the organization.
* The response includes `nextPageToken` and `previousPageToken`.

Example Response:

```json
{
  "members": [
    {
      "id": "usr-01hzy6abc123def456ghi789j",
      "authId": "user_2abcDEFghiJKL",
      "email": "alex@example.com",
      "name": "Alex Example",
      "orgId": "org-49440c77dc13f38d",
      "createdAt": "2026-03-30T14:28:03Z",
      "updatedAt": "2026-03-30T14:28:03Z",
      "roles": [
        {
          "id": "rol-01hzy7orgadmin123456789",
          "orgId": "org-49440c77dc13f38d",
          "name": "Organization admin",
          "builtin": true,
          "orgLevel": true,
          "createdAt": "2026-03-30T14:28:03Z",
          "updatedAt": "2026-03-30T14:28:03Z"
        }
      ]
    }
  ],
  "nextPageToken": "..."
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/members
```

#### Get a member

Endpoint: GET /api/v1/members/{userId}

Return the matching member record.

Path parameters:

* **userId** (required) member user ID

Response:

* Returns member identity and role information.
* The response includes publication access details in `automations` for member detail responses.
* Each item in `automations` uses the lightweight `MemberAutomation` shape with `id`, `name`, and `writeAccess`.
* The `roles` and `automations` arrays may be empty.
* The `roles` payload matches the role API response, includes `orgLevel` for org-level roles, and omits `deletedAt`.

Example Response:

```json
{
  "id": "usr-01hzy6abc123def456ghi789j",
  "authId": "user_2abcDEFghiJKL",
  "email": "alex@example.com",
  "name": "Alex Example",
  "orgId": "org-49440c77dc13f38d",
  "createdAt": "2026-03-30T14:28:03Z",
  "updatedAt": "2026-03-30T14:28:03Z",
  "roles": [
    {
      "id": "rol-01hzy7orgadmin123456789",
      "orgId": "org-49440c77dc13f38d",
      "name": "Organization admin",
      "builtin": true,
      "orgLevel": true,
      "createdAt": "2026-03-30T14:28:03Z",
      "updatedAt": "2026-03-30T14:28:03Z"
    }
  ],
  "automations": [
    {
      "id": "aut-01hzy4p1v2w3x4y5z6a7b8c9d",
      "name": "Product docs writer",
      "writeAccess": true
    },
    {
      "id": "aut-01hzy4p1v2w3x4y5z6a7b8c9e",
      "name": "Release notes writer",
      "writeAccess": false
    }
  ]
}
```

cURL Example:

```shell
curl -H "Authorization: Bearer <token>" \
  https://api.doc.holiday/api/v1/members/usr-01hzy6abc123def456ghi789j
```

### Instruction Library API

The Instruction Library API manages reusable instructions.

#### List instructions

Endpoint: GET /api/v1/instructions

Return instruction records for the authenticated organization.

Query parameters:

* **type** (optional): instruction type filter
* **global** (optional boolean): global library filter
* **query** (optional): search text for matching instructions
* **next** (optional): pagination cursor
* **pageSize** (optional): items per page

Response:

* Returns a list keyed by `instructions`.
* The list supports instruction type filtering, the global filter, search, and pagination.

#### Get an instruction

Endpoint: GET /api/v1/instructions/{id}

Return the matching instruction record.

Path parameters:

* **id** (required) instruction ID

#### Create an instruction

Endpoint: POST /api/v1/instructions

Create an instruction record.

Request:

* **name** instruction name
* **type** instruction type
* **content** (required) instruction content. Empty-string content is rejected.

Response:

* Returns the created instruction record.

Breaking change: global instructions with matching `name` and `type` now return a conflict error. Global instructions with the same `name` and a different `type` remain valid. Local instructions are exempt from this uniqueness rule.

#### Update an instruction

Endpoint: PUT /api/v1/instructions/{id}

Update an existing instruction record.

Path parameters:

* **id** (required) instruction ID

Request:

* **name** instruction name
* **type** instruction type
* **content** (required) instruction content. Empty-string content is rejected.

Response:

* Returns the updated instruction record.

#### Delete an instruction

Endpoint: DELETE /api/v1/instructions/{id}

Delete an instruction record.

Path parameters:

* **id** (required) instruction ID

Response:

* Returns `204 No Content`.
* Deleting an instruction also removes its links.

#### Create an instruction link

Endpoint: POST /api/v1/instructions/{id}/links

Create a link from an instruction to an automation slot.

Path parameters:

* **id** (required) instruction ID

Request:

* **automationId** automation ID
* **slotType** instruction slot type

Response:

* Returns the instruction link record.

#### Create instruction links in bulk

Endpoint: POST /api/v1/instructions/{id}/links/bulk

Attach one instruction to multiple automation IDs and slot types.

Path parameters:

* **id** (required) instruction ID

Request:

* **automationIds** automation IDs
* **slotTypes** slot types

Response:

* Returns the created instruction link records.

#### List instruction links

Endpoint: GET /api/v1/instruction-links

Query parameters:

* **instructionId** (optional)
* **automationId** (optional)
* **slotType** (optional)

Response:

* Returns a list keyed by `instructionLinks`.
* The list supports filtering by instruction, automation, and slot type.

#### Get an instruction link

Endpoint: GET /api/v1/instruction-links/{id}

Path parameters:

* **id** (required) instruction link ID

#### Delete an instruction link

Endpoint: DELETE /api/v1/instruction-links/{id}

Path parameters:

* **id** (required) instruction link ID

Response:

* Returns `204 No Content`.

#### Bulk delete instruction links

Endpoint: POST /api/v1/instruction-links/bulk-delete

Request:

* **ids** instruction link IDs to remove

Response:

* Returns `204 No Content`.

Linked instructions take precedence over inline slot text and fall back to inline content when no live links remain.
