# Write Semantics

This guide explains how the Kordiam API uses `POST`, `PUT`, `PATCH`, and `DELETE`.

Use it as a concepts-level map. The [API reference](/api) remains the source of truth for
exact request, response, and field-level contract details.

## `POST` Creates Resources Or Executes Commands

Use `POST` to create new resources such as stories or events, tasks, publications, groups,
platforms, categories, types, absences, and shift day notes.

Create payloads may omit optional branches. If the addressed resource defines a documented default
for a field, the create flow may apply that default when the field is omitted.

Field descriptions in the API reference should repeat that behavior explicitly where it applies.

Examples:

- `POST /api/v2/elements`
- `POST /api/v2/elements/{id}/tasks`
- `POST /api/v2/elements/{id}/publications`

`POST` is also used for action-style operations that are not resource replacement.

Examples:

- `POST /api/v2/elements/{id}/publications/{publicationId}/publish`
- `POST /api/v2/elements/{id}/external-element/link`
- `POST /api/v2/elements/{id}/external-element/unlink`
- `POST /api/v2/elements/{id}/tasks/done-state`

What to expect:

- Optional create fields may stay unset.
- Some resources define documented create-time defaults. When they do, field descriptions in the
  API reference call that out explicitly.
- Explicit invalid IDs or codes return an error instead of silently falling back to another value.
- Some `POST` endpoints create resources, while others perform named actions or transitions.

## `PUT` Replaces The Addressed Writable Resource

Use `PUT` when the client replaces the writable state of the addressed resource or subresource.

:::caution{title="PUT replaces, it does not merge"}

- `PUT` is replacement-oriented, not merge-oriented.
- Omitted fields do not mean "leave unchanged".

:::

Examples:

- `PUT /api/v2/elements/{id}`
- `PUT /api/v2/categories/{id}`
- `PUT /api/v2/elements/{id}/publications/{publicationId}/schedule`
- `PUT /api/v2/shifts/{shiftId}/notes/{date}`

What to expect:

- Required fields must be sent explicitly. Optional fields may still have replacement behavior when
  omitted; follow the field description.
- Clearable scalar or object fields may clear on omission or `null` only when the field
  description says so.
- Replacement collections may clear on omission or `[]`, while `null` is invalid where documented.

## `PATCH` Partially Updates The Addressed Writable Resource

Use `PATCH` for presence-aware partial updates.

Examples:

- `PATCH /api/v2/elements/{id}`
- `PATCH /api/v2/elements/{id}/tasks/{taskId}`
- `PATCH /api/v2/elements/{id}/publications/{publicationId}`

What to expect:

- Omitted fields remain unchanged.
- Explicit `null` clears a field only when that field documents clear-on-null semantics.
- For collection-shaped patch payloads, an empty list may mean "apply no instructions" or "clear
  the collection", depending on the endpoint contract.
- `PATCH` is used for partial resource updates, not for command-style state transitions.

## Status Field Rules

Element, task, and publication statuses are separate systems, so their no-status values differ.

| Field family | `POST` omitted / `null` | `PUT` omitted / `null` | `PATCH` omitted | `PATCH` explicit `null` |
|--------------|--------------------------|-------------------------|-----------------|--------------------------|
| Element status | Organization active default, or the No Status value when disabled or no default exists | Same as `POST` | No change | Rejected; send the No Status id to clear |
| Task status | `null` | `null` | No change | Clears to `null` |
| Publication status | The No Status value | The No Status value | No change | Rejected; send the No Status id to clear |

**No Status** is a reserved status value for elements and publications that have no assigned status.
To clear a status where the table says "send the No Status id", read the id of the No Status entry
from the matching status list endpoint — `/api/v2/element-statuses` for elements and
`/api/v2/publication-statuses` for publications.

For non-null writes, the selected status must be active and available to the organization. When a
status feature is disabled, only the system no-status value is accepted for element and publication
statuses, and task status must be `null`. Publication **Published** is not accepted through generic
status writes; use `POST /api/v2/elements/{id}/publications/{publicationId}/publish`.

## Custom-Field Empty-Value Defaults

Selection and date custom fields whose definitions disallow empty values
(`allowEmptyValue: false`) do not clear when an addressed entry carries an empty value. The API
stores a default instead: the field's first option for selection fields, the current date for date
fields. See
[Empty-Value Fallback Defaults](/docs/guides/resource-guides/custom-fields#empty-value-fallback-defaults)
for the full rules.

## `DELETE` Removes The Addressed Resource

Use `DELETE` when the addressed resource or subresource should be removed.

Examples:

- `DELETE /api/v2/platforms/{id}`
- `DELETE /api/v2/categories/{id}`
- `DELETE /api/v2/elements/{id}/tasks/{taskId}`

What to expect:

- `DELETE` applies to the addressed resource only.
- A delete can still trigger documented aggregate updates, such as removing links from related
  child collections. Standalone nested task and publication deletes do not delete the parent story
  or event when the removed item was the last one.
- Some delete endpoints complete immediately, while others return `202 Accepted` for asynchronous
  processing. Follow the response contract for the specific endpoint.
- The public contract does not rely on request bodies for `DELETE` unless an endpoint explicitly
  documents one.

## Field-Level Rules Win

Method semantics tell you the general contract shape, but field descriptions in the API reference
are the source of truth for:

- required vs optional fields
- omission vs `null`
- replacement vs instruction-list collection behavior
- create-time defaults
