# Task-Publication Linking

This page explains how tasks and publications are linked, what happens by default, and when to use
`localId` versus persisted task IDs.

Use it as narrative guidance. The [API reference](/api) remains the source of truth for exact
request and response contracts. For v1 field mapping, see
[Element Publications](/docs/migration-from-v1/publications).

## Default Behavior

:::info{title="Linking is always explicit"}

- Creating a task does not assign it to existing publications automatically.
- Creating a publication does not assign tasks automatically unless the request declares them.
- Task-publication linking is publication-driven: publications declare which tasks are linked to
  them.
- There is no reverse task field such as `assignedPublicationIds`.

:::

## Linking Modes

Use one of these two linking styles depending on the write flow.

| Write flow | Assignment field | Which task identifiers are allowed | Typical use |
|------------|------------------|------------------------------------|-------------|
| Root element `POST`, `PUT`, `PATCH` | `publications[].assignedTaskRefs` | `taskId` for existing tasks, `localId` for new tasks created in the same request | Create or update one element aggregate with nested tasks and publications |
| Standalone publication `POST`, `PATCH` | `assignedTaskIds` | Persisted task IDs only | Add or update one publication under an existing element |
| Standalone task `POST`, `PATCH` | No publication-linking field | Not applicable | Create or update a task without changing publication links |

## Root Element Writes

Root element writes can create or mutate tasks and publications in one payload. That is the only
place where `localId` is relevant.

### Root `POST /api/v2/elements`

Each nested publication must declare `assignedTaskRefs`.

- Send `assignedTaskRefs: []` to create the publication without linked tasks.
- Use `taskId` when the publication should point at an existing visible task.
- Use `localId` when the publication should point at a new task created in the same request.

Example:

```json title="Root POST with localId ref" showLineNumbers
{
  "tasks": [
    {
      "localId": "task-reporter-1",
      "statusId": 1,
      "formatId": 18,
      "confirmationStatusCode": 0,
      "user": {
        "id": 101
      }
    }
  ],
  "publications": [
    {
      "statusId": 41,
      "platformId": 101,
      "categoryId": 401,
      "typeId": 501,
      "assignedTaskRefs": [
        {
          "localId": "task-reporter-1"
        }
      ]
    }
  ]
}
```

### Root `PUT /api/v2/elements/{id}`

Root `PUT` is a strict replacement flow for nested publications and their task links.

- Each publication in the payload must declare `assignedTaskRefs`.
- `assignedTaskRefs: []` clears all task links for that publication.
- If a task is omitted from the root `PUT` payload, it can be removed as part of the full replace.
- After the request completes, the returned element body is the new source of truth.

### Root `PATCH /api/v2/elements/{id}`

Root `PATCH` is partial and presence-aware.

- If a publication patch entry includes `assignedTaskRefs`, that publication's links are replaced
  with exactly the provided refs.
- `assignedTaskRefs: []` clears the links for that publication.
- If `assignedTaskRefs` is omitted on a publication patch entry, the current links stay unchanged.
- `assignedTaskRefs: null` is invalid. Use `[]` to clear or omit the field to keep current links.

## Standalone Publication Writes

Once an element already exists, publication-task linking usually moves to the standalone publication
endpoints.

### `POST /api/v2/elements/{elementId}/publications`

Use `assignedTaskIds` to attach already-persisted tasks.

- `assignedTaskIds` accepts only persisted task IDs that belong to the same element.
- If the request contains an unknown task ID or a task from another element, the API returns
  `404 Not Found`.
- If `assignedTaskIds` is omitted, the new publication starts without linked tasks.

Example:

```json title="Standalone publication POST"
{
  "statusId": 41,
  "platformId": 401,
  "categoryId": 421,
  "typeId": 431,
  "assignedTaskIds": [3001, 3002]
}
```

### `PATCH /api/v2/elements/{elementId}/publications/{publicationId}`

Publication patch is also presence-aware.

- Send `assignedTaskIds` to replace the current linked task set.
- Unknown task IDs or task IDs from another element return `404 Not Found`.
- Send `assignedTaskIds: []` to clear all links.
- Omit `assignedTaskIds` to leave the current links unchanged.
- `assignedTaskIds: null` is invalid. Use `[]` to clear or omit the field to leave links unchanged.

Example:

```json title="Standalone publication PATCH"
{
  "assignedTaskIds": [3001]
}
```

## How `localId` Works

`localId` is a request-scoped temporary identifier for new tasks inside one root element write.

What it is for:

- Connecting `tasks[].localId` to `publications[].assignedTaskRefs[].localId` before the new task
  has a persisted ID.
- Building the initial task-publication graph in one root write request.

What it is not:

- Not a persisted task ID.
- Not reusable across requests.
- Not valid on standalone publication writes.

Rules:

- `localId` is only valid for new tasks in root element `POST`, `PUT`, and `PATCH`.
- `localId` values must be unique within the request.
- Each assignment ref must contain exactly one identifier: either `taskId` or a non-blank `localId`.
- If `taskId` is present, do not send `localId` at all, even as an empty string.
- `assignedTaskRefs[].localId` must match a task created in the same request.
- Existing tasks should be referenced by persisted `taskId`, not `localId`.

## After The Write

After a successful root write:

- Read the persisted task IDs from the returned `tasks` collection.
- Treat those persisted IDs as the canonical identifiers for later requests.
- For later standalone publication writes, switch to `assignedTaskIds`.

In other words:

- Use `localId` only inside one root write payload.
- Use persisted task IDs everywhere after that request completes.

## Common Mistakes

- Expecting a new task to be linked to every publication automatically.
- Expecting a new publication to pick up all current tasks automatically.
- Reusing a `localId` from an earlier request.
- Sending `localId` on a task that already has persisted `id`.
- Sending `localId` together with `taskId`, including an empty `localId`.
- Sending a blank `localId` without `taskId`.
- Using `assignedTaskIds` in root publication payloads instead of `assignedTaskRefs`.
- Using `localId` in standalone publication writes instead of persisted task IDs.
