> ## Documentation Index
> Fetch the complete documentation index at: https://docs.archyon.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Conventions

> Identifier formats, request semantics, and other invariants that apply across the API.

This page collects rules that apply to every endpoint. Spending five minutes here will eliminate a category of mistakes.

## Content types

All request bodies are JSON. Set both headers explicitly:

```http theme={null}
Content-Type: application/json
Accept: application/json
```

The request body size is capped at `1 MB`. Bulk replace operations on workspaces with large component counts may require splitting the payload (see [Bulk operations](#bulk-operations) below).

## Identifiers

Two identifier conventions are used.

### Slug identifiers

Resources that appear in URL paths use caller-supplied string identifiers, set at create time and immutable thereafter:

| Resource                             | Scope            |
| ------------------------------------ | ---------------- |
| Workspaces                           | Instance-wide    |
| Components, relationships, processes | Per workspace    |
| People, teams, stakeholder roles     | Per organization |

Slug identifiers are conventionally lowercase, hyphenated, and stable. The application generates kebab-case slugs from input names by default, but any string is accepted.

```
workspace: acme-prod
component: api-gateway
process:   user-signup
team:      platform
```

Two endpoints enforce a stricter pattern of `[a-z0-9][a-z0-9-]{0,48}[a-z0-9]` (2–50 characters, kebab-case, no leading or trailing hyphen): `POST /api/workspaces/{id}/processes` and `POST /api/stakeholder-link-types`. Submissions outside the pattern return `400 Bad Request`.

### Integer identifiers

Resources that are not addressed by name use server-assigned integer identifiers: API tokens, users, audit events, stakeholder links, and component external links. Integer identifiers are stable and never reused.

## Organization scoping

Most data is scoped to a Clerk organization rather than to an individual user. Organizations are the unit of multi-tenancy in Archyon.

| Resource                                                | Scope                                                  |
| ------------------------------------------------------- | ------------------------------------------------------ |
| Workspaces                                              | Per organization (binding is immutable)                |
| Components, relationships, processes, stakeholder links | Per workspace, inheriting the workspace's organization |
| People, teams, stakeholder roles                        | Per organization                                       |
| Notion integration                                      | Per organization                                       |
| Personal access tokens                                  | Bound to organization at mint time                     |

A user who belongs to multiple Clerk organizations sees an entirely independent dataset in each. There is no cross-organization join.

Instance superadministrators see all organizations on read endpoints for support purposes. The `session.isAdmin` flag returned by `GET /api/me` indicates whether the caller has this role.

## Timestamps

All timestamp fields are integer Unix milliseconds.

```json theme={null}
"createdAt": 1716566400000,
"updatedAt": 1716566500000,
"lastUsedAt": null
```

Nullable timestamp fields (such as `lastUsedAt` on tokens or `revokedAt`) return `null` when unset rather than `0` or omitted.

The single exception is the Notion proxy, which forwards Notion's own ISO 8601 strings for `lastEditedAt`:

```json theme={null}
"lastEditedAt": "2024-05-23T19:30:00.000Z"
```

## Request methods

The API uses standard HTTP method semantics with one nuance worth noting for `PATCH`.

### PATCH is a merge

`PATCH` requests apply a partial update: only fields present in the request body are modified. Omitted fields retain their existing values. To clear a nullable field, send an explicit `null` (or, in some cases, an empty string — see [Empty strings and null](#empty-strings-and-null)).

```json theme={null}
PATCH /api/people/ada-lovelace
{
  "title": "Chief Engineer",
  "email": null
}
```

This request updates `title` and clears `email`. Other fields are untouched.

### PUT replaces

`PUT` requests replace state wholesale. The only `PUT` endpoint today is `PUT /api/workspaces/{id}/bulk`, which atomically replaces every component and relationship in a workspace; see [Bulk operations](#bulk-operations) below.

### POST creates; DELETE is final

`POST` creates a resource and returns `201 Created` with the new resource in the body. `DELETE` is irreversible — there is no soft-delete or trash. Cascading deletes are noted in the endpoint documentation; for example, deleting a workspace also deletes its components, relationships, processes, stakeholder links, and membership rows.

## Immutable fields

Several fields are read-only after creation. PATCH requests that include them silently ignore the proposed change rather than returning an error.

| Field         | Applies to                                                              |
| ------------- | ----------------------------------------------------------------------- |
| `id`          | All resources                                                           |
| `orgId`       | Workspaces, people, teams, stakeholder roles                            |
| `workspaceId` | Components, relationships, processes, stakeholder links, external links |

To "move" a resource between workspaces or organizations, delete and re-create it.

## Empty strings and null

A small number of `PATCH` endpoints (`/api/people/{id}` and `/api/stakeholder-link-types/{id}`) accept an empty string `""` as equivalent to `null` for clearing nullable string fields such as `email`, `photoUrl`, `title`, `icon`, and `iconName`. Both of the following clear the email address:

```json theme={null}
{ "email": null }
{ "email": "" }
```

Required string fields treat empty or whitespace-only input as invalid and return `400 Bad Request`.

## Bulk operations

Two endpoints accept many records in a single request.

### `PUT /api/workspaces/{id}/bulk`

Replaces the workspace's entire set of components and relationships atomically. If the workspace does not yet exist it is created, and the caller becomes the owner. The body shape is:

```json theme={null}
{
  "workspace": { "id": "acme-prod", "name": "ACME Production" },
  "components": [ … ],
  "relationships": [ … ]
}
```

The `workspace.id` field must match the URL parameter or the request returns `400 Bad Request`. This endpoint backs the application's **Reset to sample data** and **Import** actions; it is destructive and intended for tooling rather than interactive use.

### Bundled read

`GET /api/workspaces/{id}` returns the workspace metadata together with every component, relationship, stakeholder link, and process. Clients should prefer this single call to issuing five separate requests when hydrating a workspace.

## Notion proxy

Endpoints under `/api/notion/*` and `/api/auth/notion/*` proxy calls to the user's connected Notion workspace. Two characteristics distinguish them from the rest of the API:

* They forward Notion's own error semantics where possible, mapping `404` to [`notion_not_found`](/errors#notion_not_found) and `401`/`403` to [`notion_access_denied`](/errors#notion_access_denied).
* They return [`notion_misconfigured`](/errors#notion_misconfigured) with `503 Service Unavailable` if the organization has not completed the Notion OAuth flow.

Treat Notion proxy failures as recoverable rather than fatal — the user can re-connect Notion or adjust page sharing without losing other Archyon state.

## Backwards compatibility

The API has no version prefix today. The following changes are considered backwards-compatible and may ship without notice:

* New endpoints
* New optional request parameters
* New fields on response bodies
* New `code` values on error responses (clients should treat unknown codes as generic errors; see [Errors › Branching on codes](/errors#branching-on-codes))

Breaking changes are announced in advance via a dashboard banner and a `Sunset` header on affected endpoints.
