# Elements

This page covers migration notes for root element reads and root element writes.

Use it together with the [Elements API reference](/api/platform/elements). The API reference remains the
source of truth for exact schemas, examples, status codes, and field-level omission or `null`
semantics.

Task, publication, schedule, task-publication linking, and custom-field value details are only
summarized here. See their dedicated guide pages and resource-specific migration pages.

## Scope

Covered v2 endpoints:

| Area | v2 endpoint |
|------|-------------|
| List elements | `GET /api/v2/elements` |
| Read one element | `GET /api/v2/elements/{id}` |
| Create root element aggregate | `POST /api/v2/elements` |
| Replace root element aggregate | `PUT /api/v2/elements/{id}` |
| Patch root element aggregate | `PATCH /api/v2/elements/{id}` |
| Read external-system bindings | `GET /api/v2/elements/{id}/external-elements` |
| Link external-system binding | `POST /api/v2/elements/{id}/external-element/link` |
| Unlink external-system binding | `POST /api/v2/elements/{id}/external-element/unlink` |
| Patch element custom fields | `PATCH /api/v2/elements/{id}/custom-fields` |

## Endpoint Mapping

:::caution{title="Do not infer paths from v1"}

Do not derive v2 paths mechanically from v1 URLs. Start from these migration patterns, then verify
the exact endpoint in `/api`.

:::

| v1 usage pattern | v2 direction |
|------------------|--------------|
| `GET .../elements/{id}` | Use `GET /api/v2/elements/{id}`. |
| Specialized element collection reads such as platform, group, no-publication, or user-based paths | Use `GET /api/v2/elements` with filter query parameters and cursor pagination. Per-endpoint mappings are listed in [List Elements Migration](#list-elements-migration). |
| `POST .../elements/` | Use `POST /api/v2/elements` with v2 request fields. |
| `PUT .../elements/{id}` | Use `PUT /api/v2/elements/{id}` for full replacement. |
| Partial root element edits | Use `PATCH /api/v2/elements/{id}` for presence-aware updates. |
| `PUT .../elements/link-external-element/{id}` | Use `POST /api/v2/elements/{id}/external-element/link`. |
| Element custom-field patch | Use `PATCH /api/v2/elements/{id}/custom-fields` and map values through [Custom-Field Migration](/docs/migration-from-v1/custom-fields). |

## List Elements Migration

v1 exposed several specialized list endpoints under `/api/v1_0_1/elements/...` for platform,
group, story-idea, no-publication, and user views. v2 unifies these into a single endpoint,
`GET /api/v2/elements`, driven by query parameters. The endpoint uses cursor pagination and
returns an `ElementListResponse` wrapper instead of a bare JSON array.

### Get Platform Elements

<CodeTabs>
  <CodeTabPanel title="v1" language="text" code={`GET /api/v1_0_1/elements/platform/{platformId}/from/{fromDate}/to/{toDate}`} />
  <CodeTabPanel title="v2" language="text" code={`GET /api/v2/elements?platformId={platformId}&dateFrom={fromDate}&dateTo={toDate}`} />
</CodeTabs>

### Get Group Elements

<CodeTabs>
  <CodeTabPanel title="v1" language="text" code={`GET /api/v1_0_1/elements/groups/{ids}`} />
  <CodeTabPanel title="v2" language="text" code={`GET /api/v2/elements?groupIds={id1},{id2}`} />
</CodeTabs>

Add `dateFrom` and `dateTo` for the publication date range.

### Get Story Ideas

<CodeTabs>
  <CodeTabPanel title="v1" language="text" code={`GET /api/v1_0_1/elements/platform/{platformId}`} />
  <CodeTabPanel title="v2" language="text" code={`GET /api/v2/elements?platformId={platformId}&storyTypes=undated`} />
</CodeTabs>

### Get Elements Without Platforms

<CodeTabs>
  <CodeTabPanel title="v1" language="text" code={`GET /api/v1_0_1/elements/no-publication-elements/{ids}`} />
  <CodeTabPanel title="v2" language="text" code={`GET /api/v2/elements?groupIds={id1},{id2}&withoutPublications=true`} />
</CodeTabs>

Use `modificationDateFrom` and `modificationDateTo` where v1 used `fromDate` and `toDate`.

### Get User Elements

<CodeTabs>
  <CodeTabPanel title="v1" language="text" code={`GET /api/v1_0_1/elements/user/{userId}`} />
  <CodeTabPanel title="v2" language="text" code={`GET /api/v2/elements?userId={userId}&deadlineFrom={fromDate}&deadlineTo={toDate}&done={true|false}&formatIds={id1},{id2}`} />
</CodeTabs>

`userId` enables user task mode and is required for `deadlineFrom`, `deadlineTo`, `done`, and
`formatIds`. When the deadline range is omitted, it defaults to today through today plus 14 days;
tasks without a deadline are included by element modification date from today minus 6 months
through today. Explicit deadline ranges must not exceed 366 days.

### General notes

- v1 endpoints returned a bare JSON array. v2 returns an `ElementListResponse` containing
  `content[]`, `size`, `hasMore`, and `nextCursor`. Follow `nextCursor` to walk the full result
  set; the endpoint is cursor-only.
- Comma-separated path IDs in v1 (for example `/groups/1,2,3`) become comma-separated query
  parameter values in v2 (`groupIds=1,2,3`). The same applies to other list filters such as
  `formatIds`.
- v1 path-based date ranges (`/from/{fromDate}/to/{toDate}`) become `dateFrom` and `dateTo`
  query parameters that accept ISO 8601 dates or date-times.

## Request Field Mapping

v2 request fields use explicit ID and code names. Common root element mappings:

| v1-style field | v2 field |
|----------------|----------|
| `elementStatus` | `elementStatusId` |
| `groups` | `groupIds` |
| `tasks[].status` | `tasks[].statusId` |
| `tasks[].format` | `tasks[].formatId` |
| `tasks[].confirmationStatus` | `tasks[].confirmationStatusCode` |
| `publications[].status` | `publications[].statusId` |
| `publications[].platform` | `publications[].platformId` |
| `publications[].category` | `publications[].categoryId` |
| `publications[].type` | `publications[].typeId` |
| `publications[].assignments` | `publications[].assignedTaskRefs` in root element writes, or `assignedTaskIds` in standalone publication writes |
| `externalElement.id` | `externalElement.externalId` |

Do not send the v2 response body back as a write request without mapping it through the relevant
request schema. Response objects include read-only IDs, URLs, timestamps, embedded references, and
server-managed metadata.

## Response Model Changes

`ElementApiModel` is an aggregate response. It can include root element fields plus nested
`tasks`, `publications`, `customFields`, `creator`, `editor`, and external-system data.

The response model uses object references where v1 clients may have parsed scalar values and
parallel name fields. Examples:

- `elementStatus` is an object reference in responses; write `elementStatusId` in requests.
- `groups` is a list of group references in responses; write `groupIds` in requests.
- publication placement uses reference objects in responses; write `platformId`, `categoryId`,
  `typeId`, and `statusId` in requests.
- task status, format, and confirmation status use response references; write `statusId`,
  `formatId`, and `confirmationStatusCode` in requests.

Clients should tolerate additive response fields and parse only the documented fields they need.

## Write Semantics

`POST /api/v2/elements` creates the root aggregate. Optional branches can be omitted when they are
not needed, but the resulting element must still satisfy the root content rule: it needs at least
one publication, one task assigned to a registered user, or one group association.

`PUT /api/v2/elements/{id}` is a full replacement of the writable root state. Notable rules:

- `confidential` is required.
- `null` is invalid for replacement collections such as `attachments`, `groupIds`, `tasks`,
  `publications`, and `customFields`.
- omitted or empty replacement collections can clear data where the field description documents
  that behavior.
- nested publication schedules are managed through the schedule subresource, not root `PUT`.

`PATCH /api/v2/elements/{id}` is presence-aware:

- omitted fields remain unchanged.
- explicit `null` clears only fields whose schema documents clear-on-null semantics.
- collection-shaped patch fields use the operation-specific behavior from the field description.
- `tasks`, `publications`, and `customFields` are instruction lists; sending `[]` means an empty
  instruction list, while `null` is invalid.

For method-level rules, see [Write Semantics](/docs/guides/api-conventions/write-semantics).

## External-System Bindings

v2 separates external-system binding commands from the root element response:

- `GET /api/v2/elements/{id}/external-elements` returns the current binding list.
- `POST /api/v2/elements/{id}/external-element/link` links or updates a binding and returns the
  refreshed binding list.
- `POST /api/v2/elements/{id}/external-element/unlink` removes a binding and returns the refreshed
  binding list.

The link request uses:

- optional `systemUrl`
- required `externalElement`
- at least one of `externalElement.externalId` or `externalElement.link`

When `systemUrl` is omitted, the API resolves the target binding from the current organization
settings.

## Status Codes And Errors

Element endpoints use the shared v2 error contract:

- `400` for invalid parameters, body shape, validation, and unsupported field values
- `401` for missing or invalid authentication
- `403` for write operations the authenticated caller cannot perform
- `404` when an element or addressed subresource is not found or not visible

Validation errors use `application/problem+json` and can include field-level `errors[]`. See
[Error Contract Changes](/docs/migration-from-v1/errors-status-codes).

## Migration Checklist For Elements

- Replace specialized v1 element collection calls with `GET /api/v2/elements` filters where
  possible.
- Re-map root write fields to explicit v2 `...Id`, `...Ids`, and `...Code` names.
- Rebuild task-publication links using `assignedTaskRefs` for root writes and `assignedTaskIds`
  for standalone publication writes.
- Treat root `PUT` as replacement and root `PATCH` as partial update.
- Manage root elements through create and update operations only.
- Parse the returned element aggregate as the refreshed state after root and nested writes.
- Update external-system link calls to the v2 link/unlink command endpoints.

## Related Guides

- [Resource Model](/docs/getting-started/data-model)
- [Write Semantics](/docs/guides/api-conventions/write-semantics)
- [JSON Model Changes](/docs/migration-from-v1/request-response-models)
- [Task-Publication Linking](/docs/guides/editorial-workflows/task-publication-linking)
- [Publication Scheduling](/docs/guides/editorial-workflows/publication-scheduling)
