# Open Mercato API

Version: 0.6.5

Auto-generated OpenAPI definition for all enabled modules.

## Servers
- https://site-dispatch.dev.evojam.com/api – Default environment

## GET `/access/users`

List users (name, email, role, status)

Requires features: access.users.view

**Tags:** Access — Users

**Requires authentication.**

**Features:** access.users.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| search | query | any | Optional |
| role | query | any | Optional |
| status | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Paginated users

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "email": "string",
      "role": null,
      "status": "active",
      "invite": null
    }
  ],
  "page": 1,
  "pageSize": 1,
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/access/users?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/access/users`

Invite a user (dispatcher or viewer)

Requires features: access.users.manage

**Tags:** Access — Users

**Requires authentication.**

**Features:** access.users.manage

### Request Body

Content-Type: `application/json`

```json
{
  "email": "string",
  "name": "string",
  "role": "dispatcher"
}
```

### Responses

**201** – Invited; emailSent=false means the account exists but the mail did not go out

Content-Type: `application/json`

```json
{
  "id": "string",
  "emailSent": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/access/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"string\",
  \"name\": \"string\",
  \"role\": \"dispatcher\"
}"
```

## GET `/access/users/{id}`

Get one user

Requires features: access.users.view

**Tags:** Access — Users

**Requires authentication.**

**Features:** access.users.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – User

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "email": "string",
  "role": null,
  "status": "active",
  "invite": null
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/access/users/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/access/users/{id}`

Change a user role (dispatcher or viewer)

Requires features: access.users.manage

**Tags:** Access — Users

**Requires authentication.**

**Features:** access.users.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "role": "dispatcher"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/access/users/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"role\": \"dispatcher\"
}"
```

## POST `/access/users/{id}/resend-invite`

Resend the invitation email (invalidates earlier invite links)

Requires features: access.users.manage

**Tags:** Access — Users

**Requires authentication.**

**Features:** access.users.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – New link issued; emailSent=false means the mail did not go out

Content-Type: `application/json`

```json
{
  "emailSent": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – User already set a password

Content-Type: `application/json`

```json
{
  "code": "user_already_active"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/access/users/:id/resend-invite" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/alerts/alerts`

List alert center items

Requires features: alerts.view

**Tags:** Alerts — Alert Center

**Requires authentication.**

**Features:** alerts.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| jobSiteIds | query | any | Optional |
| subjectType | query | any | Optional |
| subjectIds | query | any | Optional |
| kinds | query | any | Optional |
| urgencies | query | any | Optional |
| unreadOnly | query | any | Optional |
| resolved | query | any | Optional |

### Responses

**200** – Paginated alerts

Content-Type: `application/json`

```json
{
  "items": [
    {
      "alertId": "string",
      "notificationId": null,
      "kind": "subject_overlap_same_site",
      "urgency": "critical",
      "read": true,
      "jobSites": [
        {
          "id": "string",
          "name": "string"
        }
      ],
      "conflictingAssignmentIds": [
        "string"
      ],
      "occurredAt": "string",
      "linkHref": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "unreadCount": 1
}
```

**400** – Invalid filters

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/alerts/alerts?page=1&pageSize=20&resolved=false" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/alerts/alerts/{id}/read`

Mark an alert as read for the current user

Requires features: alerts.view

**Tags:** Alerts — Alert Center

**Requires authentication.**

**Features:** alerts.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Marked as read

Content-Type: `application/json`

```json
{
  "id": "string",
  "read": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/alerts/alerts/string/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/alerts/alerts/read-all`

Mark all of the current user's alerts as read

Requires features: alerts.view

**Tags:** Alerts — Alert Center

**Requires authentication.**

**Features:** alerts.view

### Responses

**200** – Marked all as read

Content-Type: `application/json`

```json
{
  "updated": 1
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/alerts/alerts/read-all" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/audit_logs/audit-logs/access`

Retrieve access logs

Fetches paginated access audit logs scoped to the authenticated user. Tenant administrators can optionally expand the search to other actors or organizations.

Requires features: audit_logs.view_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.view_self

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter by actor user id (tenant administrators only) |
| resourceKind | query | any | Optional. Restrict to a resource kind such as `order` or `product` |
| accessType | query | any | Optional. Access type filter, e.g. `read` or `export` |
| page | query | any | Optional. Page number (default 1) |
| pageSize | query | any | Optional. Page size (default 50) |
| limit | query | any | Optional. Explicit maximum number of records when paginating manually |
| before | query | any | Optional. Return logs created before this ISO-8601 timestamp |
| after | query | any | Optional. Return logs created after this ISO-8601 timestamp |

### Responses

**200** – Access logs returned successfully

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "resourceKind": "string",
      "resourceId": "string",
      "accessType": "string",
      "actorUserId": null,
      "actorUserName": null,
      "tenantId": null,
      "tenantName": null,
      "organizationId": null,
      "organizationName": null,
      "fields": [
        "string"
      ],
      "context": null,
      "createdAt": "string"
    }
  ],
  "canViewTenant": true,
  "page": 1,
  "pageSize": 1,
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid filters supplied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/audit_logs/audit-logs/access" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/audit_logs/audit-logs/actions`

Fetch action logs

Returns recent action audit log entries. Tenant administrators can widen the scope to other actors or organizations, and callers can optionally restrict results to undoable actions.

Requires features: audit_logs.view_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.view_self

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter logs created by specific actor IDs (tenant administrators only). Accepts a single UUID or a comma-separated UUID list. |
| resourceKind | query | any | Optional. Filter by resource kind (e.g., "order", "product") |
| resourceId | query | any | Optional. Filter by resource ID (UUID of the specific record) |
| actionType | query | any | Optional. Filter by action type (`create`, `edit`, `delete`, `assign`). Accepts a single value or a comma-separated list. |
| fieldName | query | any | Optional. Filter to entries where the given field changed. Accepts a single field name or a comma-separated list. |
| includeRelated | query | any | Optional. When `true`, also returns changes to child entities linked via parentResourceKind/parentResourceId |
| includeTotal | query | any | Optional. When `true`, the response includes the filtered total count. |
| undoableOnly | query | any | Optional. When `true`, only undoable actions are returned |
| limit | query | any | Optional. Maximum number of records to return (default 50, max 1000) |
| offset | query | any | Optional. Zero-based record offset for pagination (legacy — prefer page/pageSize) |
| page | query | any | Optional. Page number (default 1) |
| pageSize | query | any | Optional. Page size (default 50, max 200) |
| sortField | query | any | Optional. Sort field: `createdAt`, `user`, `action`, `field`, or `source`. |
| sortDir | query | any | Optional. Sort direction: `asc` or `desc`. |
| before | query | any | Optional. Return actions created before this ISO-8601 timestamp |
| after | query | any | Optional. Return actions created after this ISO-8601 timestamp |

### Responses

**200** – Action logs retrieved successfully

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "commandId": "string",
      "actionLabel": null,
      "executionState": "done",
      "actorUserId": null,
      "actorUserName": null,
      "tenantId": null,
      "tenantName": null,
      "organizationId": null,
      "organizationName": null,
      "resourceKind": null,
      "resourceId": null,
      "parentResourceKind": null,
      "parentResourceId": null,
      "undoToken": null,
      "createdAt": "string",
      "updatedAt": "string",
      "snapshotBefore": null,
      "snapshotAfter": null,
      "changes": null,
      "context": null
    }
  ],
  "canViewTenant": true,
  "page": 1,
  "pageSize": 1,
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid filter values

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/audit_logs/audit-logs/actions?includeRelated=false&includeTotal=false&undoableOnly=false" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/audit_logs/audit-logs/actions/export`

Export action logs as CSV

Returns a CSV attachment containing filtered action audit log entries. Tenant administrators can widen the scope to other actors or organizations.

Requires features: audit_logs.view_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.view_self

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter logs created by specific actor IDs (tenant administrators only). Accepts a single UUID or a comma-separated UUID list. |
| resourceKind | query | any | Optional. Filter by resource kind (e.g., "order", "product") |
| resourceId | query | any | Optional. Filter by resource ID (UUID of the specific record) |
| actionType | query | any | Optional. Filter by action type (`create`, `edit`, `delete`, `assign`). Accepts a single value or a comma-separated list. |
| fieldName | query | any | Optional. Filter to entries where the given field changed. Accepts a single field name or a comma-separated list. |
| includeRelated | query | any | Optional. When `true`, also returns changes to child entities linked via parentResourceKind/parentResourceId |
| undoableOnly | query | any | Optional. When `true`, only undoable actions are returned |
| limit | query | any | Optional. Maximum number of records to export (default 1000, capped at 1000) |
| sortField | query | any | Optional. Sort field: `createdAt`, `user`, `action`, `field`, or `source`. |
| sortDir | query | any | Optional. Sort direction: `asc` or `desc`. |
| before | query | any | Optional. Return actions created before this ISO-8601 timestamp |
| after | query | any | Optional. Return actions created after this ISO-8601 timestamp |

### Responses

**200** – CSV export generated successfully

Content-Type: `application/json`

```json
{
  "file": "csv"
}
```

**400** – Invalid filter values

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/audit_logs/audit-logs/actions/export?includeRelated=false&undoableOnly=false" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/audit_logs/audit-logs/actions/redo`

Redo by action log id

Redoes the latest undone command owned by the caller. Requires the action to still be eligible for redo within tenant and organization scope.

Requires features: audit_logs.redo_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.redo_self

### Request Body

Content-Type: `application/json`

```json
{
  "logId": "string"
}
```

### Responses

**200** – Redo executed successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "logId": null,
  "undoToken": null
}
```

**400** – Log not eligible for redo

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/audit_logs/audit-logs/actions/redo" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"logId\": \"string\"
}"
```

## POST `/audit_logs/audit-logs/actions/undo`

Undo action by token

Replays the undo handler registered for a command. The provided undo token must match the latest undoable log entry accessible to the caller.

Requires features: audit_logs.undo_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.undo_self

### Request Body

Content-Type: `application/json`

```json
{
  "undoToken": "string"
}
```

### Responses

**200** – Undo applied successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "logId": "string"
}
```

**400** – Invalid or unavailable undo token

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/audit_logs/audit-logs/actions/undo" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"undoToken\": \"string\"
}"
```

## GET `/auth/admin/nav`

Resolve backend chrome bootstrap payload

Returns the backend chrome payload available to the authenticated administrator after applying scope, RBAC, role defaults, and personal sidebar preferences.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Backend chrome payload

Content-Type: `application/json`

```json
{
  "brand": null,
  "groups": [
    {
      "name": "string",
      "items": [
        {
          "href": "string",
          "title": "string"
        }
      ]
    }
  ],
  "settingsSections": [
    {
      "id": "string",
      "label": "string",
      "items": [
        {
          "id": "string",
          "label": "string",
          "href": "string"
        }
      ]
    }
  ],
  "settingsPathPrefixes": [
    "string"
  ],
  "profileSections": [
    {
      "id": "string",
      "label": "string",
      "items": [
        {
          "id": "string",
          "label": "string",
          "href": "string"
        }
      ]
    }
  ],
  "profilePathPrefixes": [
    "string"
  ],
  "grantedFeatures": [
    "string"
  ],
  "roles": [
    "string"
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/admin/nav" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/feature-check`

Check feature grants for the current user

Evaluates which of the requested features are available to the signed-in user within the active tenant / organization context.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "features": [
    "string"
  ]
}
```

### Responses

**200** – Evaluation result

Content-Type: `application/json`

```json
{
  "ok": true,
  "granted": [
    "string"
  ],
  "userId": "string"
}
```

**400** – Invalid request — features array missing, too large, or contains invalid entries

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/feature-check" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"features\": [
    \"string\"
  ]
}"
```

## GET `/auth/features`

List declared feature flags

Returns all static features contributed by the enabled modules along with their module source.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### Responses

**200** – Aggregated feature catalog

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "module": "string"
    }
  ],
  "modules": [
    {
      "id": "string",
      "title": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/features" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/locale`

Set locale and redirect

Stores the selected locale in a cookie and redirects to a safe local path.

**Tags:** Authentication & Accounts

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| locale | query | any | Required |
| redirect | query | any | Optional |

### Responses

**200** – Success response

Content-Type: `application/json`

**302** – Locale cookie set and request redirected

Content-Type: `application/json`

**400** – Invalid locale

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/locale?locale=en" \
  -H "Accept: application/json"
```

## POST `/auth/locale`

Set locale

Stores the selected locale in a cookie and returns a JSON success response.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "locale": "en"
}
```

### Responses

**200** – Locale cookie set

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid locale or malformed request body

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/locale" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"locale\": \"en\"
}"
```

## POST `/auth/login`

Authenticate user credentials

Validates the submitted credentials and issues a bearer token cookie for subsequent API calls.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/x-www-form-urlencoded`

```text
email=user%40example.com&password=string
```

### Responses

**200** – Authentication succeeded

Content-Type: `application/json`

```json
{
  "ok": true,
  "token": "string",
  "redirect": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**401** – Invalid credentials

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**403** – User lacks required role

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**429** – Too many login attempts

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user%40example.com&password=string"
```

## POST `/auth/logout`

Invalidate session and redirect

Clears authentication cookies and redirects the browser to the login page.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

**302** – Redirect to login after successful logout

Content-Type: `text/html`

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/logout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/profile`

Get current profile

Returns the email address for the signed-in user.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Profile payload

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roles": [
    "string"
  ]
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/profile" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/profile`

Update current profile

Updates the email address or password for the signed-in user.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Profile updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "email": "user@example.com"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/profile" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/auth/reset`

Send reset email

Requests a password reset email for the given account. The endpoint always returns `ok: true` to avoid leaking account existence.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/x-www-form-urlencoded`

```text
email=user%40example.com
```

### Responses

**200** – Reset email dispatched (or ignored for unknown accounts)

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request origin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**429** – Too many password reset requests

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Password reset email origin is not configured

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/reset" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user%40example.com"
```

## POST `/auth/reset/confirm`

Complete password reset

Validates the reset token and updates the user password.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/x-www-form-urlencoded`

```text
token=string&password=string
```

### Responses

**200** – Password reset succeeded

Content-Type: `application/json`

```json
{
  "ok": true,
  "redirect": "string"
}
```

**400** – Invalid token or payload

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**429** – Too many reset confirmation attempts

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/reset/confirm" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=string&password=string"
```

## DELETE `/auth/roles`

Delete role

Deletes a role by identifier. Fails when users remain assigned.

Requires features: auth.roles.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. Role identifier |

### Responses

**200** – Role deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Role cannot be deleted

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/auth/roles?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/roles`

List roles

Returns available roles within the current tenant. Super administrators receive visibility across tenants.

Requires features: auth.roles.list

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.list

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| tenantId | query | any | Optional |

### Responses

**200** – Role collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "usersCount": 1,
      "tenantId": null,
      "tenantName": null,
      "updatedAt": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/roles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/roles`

Create role

Creates a new role for the current tenant or globally when `tenantId` is omitted.

Requires features: auth.roles.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string"
}
```

### Responses

**201** – Role created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\"
}"
```

## PUT `/auth/roles`

Update role

Updates mutable fields on an existing role.

Requires features: auth.roles.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Role updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/auth/roles/acl`

Fetch role ACL

Returns the feature and organization assignments associated with a role within the current tenant.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| roleId | query | any | Required |
| tenantId | query | any | Optional |

### Responses

**200** – Role ACL entry

Content-Type: `application/json`

```json
{
  "isSuperAdmin": true,
  "features": [
    "string"
  ],
  "organizations": null,
  "updatedAt": null
}
```

**400** – Invalid role id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/roles/acl?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/roles/acl`

Update role ACL

Replaces the feature list, super admin flag, and optional organization assignments for a role.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### Request Body

Content-Type: `application/json`

```json
{
  "roleId": "00000000-0000-4000-8000-000000000000",
  "organizations": null
}
```

### Responses

**200** – Role ACL updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "sanitized": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/roles/acl" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizations\": null
}"
```

## GET `/auth/session/refresh`

Refresh auth cookie from session token (browser)

Exchanges an existing `session_token` cookie for a fresh JWT auth cookie and redirects the browser.

**Tags:** Authentication & Accounts

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| redirect | query | any | Optional. Absolute or relative URL to redirect after refresh |

### Responses

**200** – Success response

Content-Type: `application/json`

**302** – Redirect to target location when session is valid

Content-Type: `text/html`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/session/refresh" \
  -H "Accept: application/json"
```

## POST `/auth/session/refresh`

Refresh access token (API/mobile)

Exchanges a refresh token for a new JWT access token. Pass the refresh token obtained from login in the request body.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "refreshToken": "string"
}
```

### Responses

**200** – New access token issued

Content-Type: `application/json`

```json
{
  "ok": true,
  "accessToken": "string",
  "expiresIn": 1
}
```

**400** – Missing refresh token

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**401** – Invalid or expired token

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**429** – Too many refresh attempts

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/session/refresh" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"refreshToken\": \"string\"
}"
```

## DELETE `/auth/sidebar/preferences`

Delete a role sidebar variant

Removes the role variant for the current tenant + locale. Idempotent. Requires `auth.sidebar.manage`.

Requires features: auth.sidebar.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.sidebar.manage

### Responses

**200** – Variant deleted (or never existed)

Content-Type: `application/json`

```json
{
  "ok": true,
  "scope": {
    "type": "user"
  }
}
```

**400** – Missing roleId query parameter

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in current tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/sidebar/preferences`

Get sidebar preferences

Returns sidebar customization for the current user (default) or the specified role (`?roleId=…`, requires `auth.sidebar.manage`).

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Current sidebar configuration

Content-Type: `application/json`

```json
{
  "locale": "string",
  "settings": {
    "version": 1,
    "groupOrder": [
      "string"
    ],
    "groupLabels": {
      "key": "string"
    },
    "itemLabels": {
      "key": "string"
    },
    "hiddenItems": [
      "string"
    ],
    "itemOrder": {
      "key": [
        "string"
      ]
    }
  },
  "canApplyToRoles": true,
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPreference": true
    }
  ],
  "scope": {
    "type": "user"
  },
  "updatedAt": null
}
```

**403** – Missing features for role-scope read

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in current tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/sidebar/preferences`

Update sidebar preferences

Updates sidebar configuration. With `scope.type === "user"` (default) writes the calling user's personal preferences and may optionally apply the same settings to selected roles via `applyToRoles[]`. With `scope.type === "role"` writes the named role variant directly (requires `auth.sidebar.manage`); `applyToRoles[]` and `clearRoleIds[]` are rejected in this mode.

Requires features: auth.sidebar.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.sidebar.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Preferences saved

Content-Type: `application/json`

```json
{
  "locale": "string",
  "settings": {
    "version": 1,
    "groupOrder": [
      "string"
    ],
    "groupLabels": {
      "key": "string"
    },
    "itemLabels": {
      "key": "string"
    },
    "hiddenItems": [
      "string"
    ],
    "itemOrder": {
      "key": [
        "string"
      ]
    }
  },
  "canApplyToRoles": true,
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPreference": true
    }
  ],
  "scope": {
    "type": "user"
  },
  "updatedAt": null,
  "appliedRoles": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "clearedRoles": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in current tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/auth/sidebar/variants`

List sidebar variants

Returns the named sidebar variants saved by the current user for the current tenant + locale.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Variant list

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variants": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true,
      "settings": {
        "version": 1,
        "groupOrder": [
          "string"
        ],
        "groupLabels": {
          "key": "string"
        },
        "itemLabels": {
          "key": "string"
        },
        "hiddenItems": [
          "string"
        ],
        "itemOrder": {
          "key": [
            "string"
          ]
        }
      },
      "createdAt": "string",
      "updatedAt": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/sidebar/variants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/sidebar/variants`

Create a sidebar variant

Creates a new variant. If `name` is omitted or blank, an auto-name like "My preferences", "My preferences 2", … is assigned.

Requires features: auth.sidebar.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.sidebar.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Variant created

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variant": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "isActive": true,
    "settings": {
      "version": 1,
      "groupOrder": [
        "string"
      ],
      "groupLabels": {
        "key": "string"
      },
      "itemLabels": {
        "key": "string"
      },
      "hiddenItems": [
        "string"
      ],
      "itemOrder": {
        "key": [
          "string"
        ]
      }
    },
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/sidebar/variants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/auth/sidebar/variants/{id}`

Delete a sidebar variant

Soft-deletes the variant (sets deleted_at).

Requires features: auth.sidebar.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.sidebar.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Variant deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**404** – Variant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/auth/sidebar/variants/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/sidebar/variants/{id}`

Get a sidebar variant

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Variant

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variant": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "isActive": true,
    "settings": {
      "version": 1,
      "groupOrder": [
        "string"
      ],
      "groupLabels": {
        "key": "string"
      },
      "itemLabels": {
        "key": "string"
      },
      "hiddenItems": [
        "string"
      ],
      "itemOrder": {
        "key": [
          "string"
        ]
      }
    },
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**404** – Variant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/sidebar/variants/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/sidebar/variants/{id}`

Update a sidebar variant

Updates the variant's name, settings, and/or isActive flag. Setting `isActive: true` deactivates other variants in the same scope (only one active per user/tenant/locale).

Requires features: auth.sidebar.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.sidebar.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Variant updated

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variant": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "isActive": true,
    "settings": {
      "version": 1,
      "groupOrder": [
        "string"
      ],
      "groupLabels": {
        "key": "string"
      },
      "itemLabels": {
        "key": "string"
      },
      "hiddenItems": [
        "string"
      ],
      "itemOrder": {
        "key": [
          "string"
        ]
      }
    },
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Variant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/sidebar/variants/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/auth/users`

Delete user

Deletes a user by identifier. Undo support is provided via the command bus.

Requires features: auth.users.delete

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.delete

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. User identifier |

### Responses

**200** – User deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – User cannot be deleted

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/auth/users?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/users`

List users

Returns users for the effective selected tenant and organization scope. Search matches email, organization name, and role name. Super administrators may scope the response via the topbar context, organization filters, or role filters.

Requires features: auth.users.list

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.list

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| name | query | any | Optional |
| organizationId | query | any | Optional |
| roleIds | query | any | Optional |

### Responses

**200** – User collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "email": "user@example.com",
      "name": null,
      "organizationId": null,
      "organizationName": null,
      "tenantId": null,
      "tenantName": null,
      "roles": [
        "string"
      ],
      "updatedAt": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/users?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/users`

Create user

Creates a new confirmed user within the specified organization, optional display name, and optional roles.

Requires features: auth.users.create

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.create

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "name": null,
  "organizationId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – User created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid payload or duplicate email

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"name\": null,
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/auth/users`

Update user

Updates profile fields including display name, organization assignment, credentials, or role memberships.

Requires features: auth.users.edit

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.edit

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "name": null
}
```

### Responses

**200** – User updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": null
}"
```

## GET `/auth/users/acl`

Fetch user ACL

Returns custom ACL overrides for a user within the current tenant, if any.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| userId | query | any | Required |

### Responses

**200** – User ACL entry

Content-Type: `application/json`

```json
{
  "hasCustomAcl": true,
  "isSuperAdmin": true,
  "features": [
    "string"
  ],
  "organizations": null,
  "updatedAt": null
}
```

**400** – Invalid user id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/users/acl?userId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/users/acl`

Update user ACL

Configures per-user ACL overrides, including super admin access, feature list, and organization scope.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### Request Body

Content-Type: `application/json`

```json
{
  "userId": "00000000-0000-4000-8000-000000000000",
  "organizations": null
}
```

### Responses

**200** – User ACL updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "sanitized": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/auth/users/acl" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizations\": null
}"
```

## GET `/auth/users/consents`

List user consents

Returns all consent records for a given user, with integrity verification status.

Requires features: auth.users.edit

**Tags:** Auth

**Requires authentication.**

**Features:** auth.users.edit

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| userId | query | any | Required |

### Responses

**200** – Consent list returned

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/auth/users/consents?userId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/users/resend-invite`

Resend invitation email

Resends the invitation email to a user who has not yet set up their password. Generates a new 48-hour setup token and invalidates prior tokens.

Requires features: auth.users.create

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.create

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Invite email sent

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request origin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – User already has a password

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**422** – Validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**429** – Rate limit exceeded

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Invitation email origin is not configured

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/auth/users/resend-invite" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/calendar/availability-windows`

Create an unavailability window

Requires features: calendar.manage

**Tags:** Calendar — Availability Windows

**Requires authentication.**

**Features:** calendar.manage

### Request Body

Content-Type: `application/json`

```json
{
  "resourceType": "equipment",
  "resourceId": "string",
  "startDate": "string",
  "endDateExclusive": "string",
  "reasonCode": "in_service"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/calendar/availability-windows" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"resourceType\": \"equipment\",
  \"resourceId\": \"string\",
  \"startDate\": \"string\",
  \"endDateExclusive\": \"string\",
  \"reasonCode\": \"in_service\"
}"
```

## DELETE `/calendar/availability-windows/{id}`

Delete an unavailability window

Requires features: calendar.manage

**Tags:** Calendar — Availability Windows

**Requires authentication.**

**Features:** calendar.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deleted

Content-Type: `application/json`

```json
{
  "deleted": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/calendar/availability-windows/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/calendar/availability-windows/{id}`

Get an unavailability window

Requires features: calendar.view

**Tags:** Calendar — Availability Windows

**Requires authentication.**

**Features:** calendar.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Window detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "resourceType": "equipment",
  "resourceId": "string",
  "startAt": "string",
  "endAt": "string",
  "reasonCode": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/calendar/availability-windows/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/calendar/availability-windows/{id}`

Update an unavailability window

Requires features: calendar.manage

**Tags:** Calendar — Availability Windows

**Requires authentication.**

**Features:** calendar.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "note": null
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/calendar/availability-windows/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"note\": null
}"
```

## GET `/calendar/unavailability-reasons`

List unavailability reasons

Requires features: calendar.view

**Tags:** Calendar — Unavailability Reasons

**Requires authentication.**

**Features:** calendar.view

### Responses

**200** – Seeded reasons dictionary

Content-Type: `application/json`

```json
[
  {
    "code": "string",
    "resourceType": "equipment"
  }
]
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/calendar/unavailability-reasons" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/calendar/working-calendar`

Get the org working calendar

Requires features: calendar.view

**Tags:** Calendar — Working Calendar

**Requires authentication.**

**Features:** calendar.view

### Responses

**200** – Org working calendar

Content-Type: `application/json`

```json
{
  "timeZone": "string",
  "offWeekdays": [
    "mon"
  ],
  "holidays": [
    {
      "id": "string",
      "date": "string",
      "name": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/calendar/working-calendar" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/calendar/working-calendar`

Replace the org working calendar (weekly free days + holidays)

Requires features: calendar.manage

**Tags:** Calendar — Working Calendar

**Requires authentication.**

**Features:** calendar.manage

### Request Body

Content-Type: `application/json`

```json
{
  "timeZone": "string",
  "offWeekdays": [
    "mon"
  ],
  "holidays": [
    {
      "date": "string"
    }
  ]
}
```

### Responses

**200** – Updated working calendar

Content-Type: `application/json`

```json
{
  "timeZone": "string",
  "offWeekdays": [
    "mon"
  ],
  "holidays": [
    {
      "id": "string",
      "date": "string",
      "name": "string"
    }
  ]
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/calendar/working-calendar" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"timeZone\": \"string\",
  \"offWeekdays\": [
    \"mon\"
  ],
  \"holidays\": [
    {
      \"date\": \"string\"
    }
  ]
}"
```

## GET `/configs/cache`

Get cache statistics

Returns detailed cache statistics including total entries and breakdown by cache segments. Requires cache service to be available.

Requires features: configs.cache.view

**Tags:** Configs

**Requires authentication.**

**Features:** configs.cache.view

### Responses

**200** – Cache statistics

Content-Type: `application/json`

```json
{
  "generatedAt": "string",
  "totalKeys": 1,
  "segments": [
    {
      "segment": "string",
      "resource": null,
      "method": null,
      "path": null,
      "keyCount": 1,
      "keys": [
        "string"
      ]
    }
  ]
}
```

**500** – Failed to resolve cache stats

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**503** – Cache service unavailable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/configs/cache" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/configs/cache`

Purge cache

Purges cache entries. Supports two actions: purgeAll (clears entire cache) or purgeSegment (clears specific segment). Returns updated cache statistics after purge.

Requires features: configs.cache.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.cache.manage

### Request Body

Content-Type: `application/json`

```json
{
  "action": "purgeAll"
}
```

### Responses

**200** – Cache segment cleared successfully

Content-Type: `application/json`

```json
{
  "action": "purgeSegment",
  "segment": "string",
  "deleted": 1,
  "stats": {
    "generatedAt": "string",
    "totalKeys": 1,
    "segments": [
      {
        "segment": "string",
        "resource": null,
        "method": null,
        "path": null,
        "keyCount": 1,
        "keys": [
          "string"
        ]
      }
    ]
  }
}
```

**400** – Invalid request - missing segment identifier for purgeSegment action

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to purge cache

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**503** – Cache service unavailable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/configs/cache" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"action\": \"purgeAll\"
}"
```

## GET `/configs/system-status`

Get system health status

Returns comprehensive system health information including environment details, version, resource usage, and service connectivity status.

Requires features: configs.system_status.view

**Tags:** Configs

**Requires authentication.**

**Features:** configs.system_status.view

### Responses

**200** – System status snapshot

Content-Type: `application/json`

```json
{
  "generatedAt": "string",
  "runtimeMode": "development",
  "categories": [
    {
      "key": "profiling",
      "labelKey": "string",
      "descriptionKey": null,
      "items": [
        {
          "key": "string",
          "category": "profiling",
          "kind": "boolean",
          "labelKey": "string",
          "descriptionKey": "string",
          "docUrl": null,
          "defaultValue": null,
          "state": "enabled",
          "value": null,
          "normalizedValue": null
        }
      ]
    }
  ]
}
```

**500** – Failed to load system status

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/configs/system-status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/configs/system-status`

Clear system cache

Purges the entire cache for the current tenant. Useful for troubleshooting or forcing fresh data loading.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### Responses

**200** – Cache cleared successfully

Content-Type: `application/json`

```json
{
  "cleared": true
}
```

**500** – Failed to purge cache

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**503** – Cache service unavailable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/configs/system-status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/configs/upgrade-actions`

List pending upgrade actions

Returns a list of pending upgrade actions for the current version. These are one-time setup tasks that need to be executed after upgrading to a new version. Requires organization and tenant context.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### Responses

**200** – List of pending upgrade actions

Content-Type: `application/json`

```json
{
  "version": "string",
  "actions": [
    {
      "id": "string",
      "version": "string",
      "message": "string",
      "ctaLabel": "string",
      "successMessage": "string",
      "loadingLabel": "string"
    }
  ]
}
```

**400** – Missing organization or tenant context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load upgrade actions

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/configs/upgrade-actions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/configs/upgrade-actions`

Execute upgrade action

Executes a specific upgrade action by ID. Typically used for one-time setup tasks like seeding example data after version upgrade. Returns execution status and localized success message.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### Request Body

Content-Type: `application/json`

```json
{
  "actionId": "string"
}
```

### Responses

**200** – Upgrade action executed successfully

Content-Type: `application/json`

```json
{
  "status": "string",
  "message": "string",
  "version": "string"
}
```

**400** – Invalid request body or missing context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to execute upgrade action

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/configs/upgrade-actions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"actionId\": \"string\"
}"
```

## GET `/dashboards/layout`

Load the current dashboard layout

Returns the saved widget layout together with the widgets the current user is allowed to place.

Requires features: dashboards.view

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.view

### Responses

**200** – Current dashboard layout and available widgets.

Content-Type: `application/json`

```json
{
  "layout": {
    "items": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "widgetId": "string",
        "order": 1
      }
    ]
  },
  "allowedWidgetIds": [
    "string"
  ],
  "canConfigure": true,
  "context": {
    "userId": "00000000-0000-4000-8000-000000000000",
    "tenantId": null,
    "organizationId": null,
    "userName": null,
    "userEmail": null,
    "userLabel": "string"
  },
  "widgets": [
    {
      "id": "string",
      "title": "string",
      "description": null,
      "defaultSize": "sm",
      "defaultEnabled": true,
      "defaultSettings": null,
      "features": [
        "string"
      ],
      "moduleId": "string",
      "icon": null,
      "loaderKey": "string",
      "supportsRefresh": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dashboards/layout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dashboards/layout`

Persist dashboard layout changes

Saves the provided widget ordering, sizes, and settings for the current user.

Requires features: dashboards.configure

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.configure

### Request Body

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "widgetId": "string",
      "order": 1
    }
  ]
}
```

### Responses

**200** – Layout updated successfully.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid layout payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dashboards/layout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"items\": [
    {
      \"id\": \"00000000-0000-4000-8000-000000000000\",
      \"widgetId\": \"string\",
      \"order\": 1
    }
  ]
}"
```

## PATCH `/dashboards/layout/{itemId}`

Update a dashboard layout item

Adjusts the size or settings for a single widget within the dashboard layout.

Requires features: dashboards.configure

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.configure

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| itemId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Layout item updated.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload or missing item id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Item not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://site-dispatch.dev.evojam.com/api/dashboards/layout/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/dashboards/roles/widgets`

Fetch widget assignments for a role

Returns the widgets explicitly assigned to the given role together with the evaluation scope.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| roleId | query | any | Required |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |

### Responses

**200** – Current widget configuration for the role.

Content-Type: `application/json`

```json
{
  "widgetIds": [
    "string"
  ],
  "hasCustom": true,
  "scope": {
    "tenantId": null,
    "organizationId": null
  }
}
```

**400** – Missing role identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dashboards/roles/widgets?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dashboards/roles/widgets`

Update widgets assigned to a role

Persists the widget list for a role within the provided tenant and organization scope.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Request Body

Content-Type: `application/json`

```json
{
  "roleId": "00000000-0000-4000-8000-000000000000",
  "widgetIds": [
    "string"
  ]
}
```

### Responses

**200** – Widgets updated successfully.

Content-Type: `application/json`

```json
{
  "ok": true,
  "widgetIds": [
    "string"
  ]
}
```

**400** – Invalid payload or unknown widgets

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dashboards/roles/widgets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleId\": \"00000000-0000-4000-8000-000000000000\",
  \"widgetIds\": [
    \"string\"
  ]
}"
```

## GET `/dashboards/users/widgets`

Read widget overrides for a user

Returns the widgets inherited and explicitly configured for the requested user within the current scope.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| userId | query | any | Required |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |

### Responses

**200** – Widget settings for the user.

Content-Type: `application/json`

```json
{
  "mode": "inherit",
  "widgetIds": [
    "string"
  ],
  "hasCustom": true,
  "effectiveWidgetIds": [
    "string"
  ],
  "scope": {
    "tenantId": null,
    "organizationId": null
  }
}
```

**400** – Missing user identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dashboards/users/widgets?userId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dashboards/users/widgets`

Update user-specific dashboard widgets

Sets the widget override mode and allowed widgets for a user. Passing `mode: inherit` clears overrides.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Request Body

Content-Type: `application/json`

```json
{
  "userId": "00000000-0000-4000-8000-000000000000",
  "mode": "inherit",
  "widgetIds": [
    "string"
  ]
}
```

### Responses

**200** – Overrides saved.

Content-Type: `application/json`

```json
{
  "ok": true,
  "mode": "inherit",
  "widgetIds": [
    "string"
  ]
}
```

**400** – Invalid payload or unknown widgets

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dashboards/users/widgets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\",
  \"mode\": \"inherit\",
  \"widgetIds\": [
    \"string\"
  ]
}"
```

## GET `/dashboards/widgets/catalog`

List available dashboard widgets

Returns the catalog of widgets that modules expose, including defaults and feature requirements.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Responses

**200** – Widgets available for assignment.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "description": null,
      "defaultSize": "sm",
      "defaultEnabled": true,
      "defaultSettings": null,
      "features": [
        "string"
      ],
      "moduleId": "string",
      "icon": null,
      "loaderKey": "string",
      "supportsRefresh": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dashboards/widgets/catalog" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dashboards/widgets/data`

Fetch aggregated data for dashboard widgets

Executes an aggregation query against the specified entity type and returns the result. Supports date range filtering, grouping, and period-over-period comparison.

Requires features: analytics.view

**Tags:** Dashboards

**Requires authentication.**

**Features:** analytics.view

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string",
  "metric": {
    "field": "string",
    "aggregate": "count"
  }
}
```

### Responses

**200** – Aggregated data for the widget.

Content-Type: `application/json`

```json
{
  "value": null,
  "data": [
    {
      "value": null
    }
  ],
  "metadata": {
    "fetchedAt": "string",
    "recordCount": 1
  }
}
```

**400** – Invalid request payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Internal server error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dashboards/widgets/data" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\",
  \"metric\": {
    \"field\": \"string\",
    \"aggregate\": \"count\"
  }
}"
```

## POST `/dashboards/widgets/data/batch`

Fetch aggregated data for multiple dashboard widgets in one request

Resolves a batch of widget data requests with a single authentication, RBAC, organization-scope, and database-context setup. Each request is keyed by an opaque widget id and resolved independently, so a failure in one widget does not fail the batch.

Requires features: analytics.view

**Tags:** Dashboards

**Requires authentication.**

**Features:** analytics.view

### Request Body

Content-Type: `application/json`

```json
{
  "requests": [
    {
      "id": "string",
      "request": {
        "entityType": "string",
        "metric": {
          "field": "string",
          "aggregate": "count"
        }
      }
    }
  ]
}
```

### Responses

**200** – Per-widget aggregation results keyed by request id.

Content-Type: `application/json`

```json
{
  "results": [
    {
      "id": "string",
      "ok": true,
      "data": {
        "value": null,
        "data": [
          {
            "value": null
          }
        ],
        "metadata": {
          "fetchedAt": "string",
          "recordCount": 1
        }
      }
    }
  ]
}
```

**400** – Invalid request payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Internal server error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dashboards/widgets/data/batch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requests\": [
    {
      \"id\": \"string\",
      \"request\": {
        \"entityType\": \"string\",
        \"metric\": {
          \"field\": \"string\",
          \"aggregate\": \"count\"
        }
      }
    }
  ]
}"
```

## GET `/dictionaries`

List dictionaries

Returns dictionaries accessible to the current organization, optionally including inactive records.

Requires features: dictionaries.view

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| includeInactive | query | any | Optional |

### Responses

**200** – Dictionary collection.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "key": "string",
      "name": "string",
      "description": null,
      "isSystem": true,
      "isActive": true,
      "managerVisibility": null,
      "organizationId": null,
      "createdAt": "string",
      "updatedAt": null
    }
  ]
}
```

**500** – Failed to load dictionaries

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dictionaries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dictionaries`

Create dictionary

Registers a dictionary scoped to the current organization.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Request Body

Content-Type: `application/json`

```json
{
  "key": "string",
  "name": "string"
}
```

### Responses

**201** – Dictionary created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "key": "string",
  "name": "string",
  "description": null,
  "isSystem": true,
  "isActive": true,
  "managerVisibility": null,
  "organizationId": null,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Dictionary key already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to create dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dictionaries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"key\": \"string\",
  \"name\": \"string\"
}"
```

## DELETE `/dictionaries/{dictionaryId}`

Delete dictionary

Soft deletes the dictionary unless it is the protected currency dictionary.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Responses

**200** – Dictionary archived.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Protected dictionary cannot be deleted

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to delete dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dictionaries/{dictionaryId}`

Get dictionary

Returns details for the specified dictionary, including inheritance flags.

Requires features: dictionaries.view

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Responses

**200** – Dictionary details.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "key": "string",
  "name": "string",
  "description": null,
  "isSystem": true,
  "isActive": true,
  "managerVisibility": null,
  "organizationId": null,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Invalid parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/dictionaries/{dictionaryId}`

Update dictionary

Updates mutable attributes of the dictionary. Currency dictionaries are protected from modification.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Dictionary updated.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "key": "string",
  "name": "string",
  "description": null,
  "isSystem": true,
  "isActive": true,
  "managerVisibility": null,
  "organizationId": null,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed or protected dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Dictionary key already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to update dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/dictionaries/{dictionaryId}/entries`

List dictionary entries

Returns entries for the specified dictionary ordered by its configured entry sort mode.

Requires features: dictionaries.view

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Responses

**200** – Dictionary entries.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": "string",
      "color": null,
      "icon": null,
      "position": 1,
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null
    }
  ]
}
```

**400** – Invalid parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load dictionary entries

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dictionaries/{dictionaryId}/entries`

Create dictionary entry

Creates a new entry in the specified dictionary.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "value": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Dictionary entry created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": "string",
  "color": null,
  "icon": null,
  "position": 1,
  "isDefault": true,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to create dictionary entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"value\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## DELETE `/dictionaries/{dictionaryId}/entries/{entryId}`

Delete dictionary entry

Deletes the specified dictionary entry via the command bus.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |
| entryId | path | any | Required |

### Responses

**200** – Entry deleted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary or entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to delete entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/dictionaries/{dictionaryId}/entries/{entryId}`

Update dictionary entry

Updates the specified dictionary entry using the command bus pipeline.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |
| entryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "color": null,
  "icon": null
}
```

### Responses

**200** – Dictionary entry updated.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": "string",
  "color": null,
  "icon": null,
  "position": 1,
  "isDefault": true,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary or entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to update entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"color\": null,
  \"icon\": null
}"
```

## POST `/dictionaries/{dictionaryId}/entries/reorder`

Reorder dictionary entries

Updates the position of dictionary entries for drag-and-drop reordering.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "entries": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "position": 1
    }
  ]
}
```

### Responses

**200** – Entries reordered.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to reorder entries

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/reorder" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entries\": [
    {
      \"id\": \"00000000-0000-4000-8000-000000000000\",
      \"position\": 1
    }
  ]
}"
```

## POST `/dictionaries/{dictionaryId}/entries/set-default`

Set default dictionary entry

Marks the specified entry as the default for this dictionary, clearing any previous default.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "entryId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Default entry set.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary or entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to set default entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/set-default" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entryId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/organization-branding`

Read sidebar branding for the selected organization

Returns the logo URL used by the backend sidebar for the currently selected organization.

Requires features: directory.organizations.view

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.view

### Responses

**200** – Organization branding

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "organizationName": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "logoUrl": null
}
```

**400** – A concrete organization scope is required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Organization not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/directory/organization-branding" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/directory/organization-branding`

Update sidebar branding for the selected organization

Stores an external image URL or an internal attachment image URL as the selected organization logo.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### Request Body

Content-Type: `application/json`

```json
{
  "logoUrl": null
}
```

### Responses

**200** – Updated organization branding

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "organizationName": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "logoUrl": null
}
```

**400** – Save failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**422** – Invalid logo URL

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/directory/organization-branding" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"logoUrl\": null
}"
```

## GET `/directory/organization-switcher`

Load organization switcher menu

Returns the hierarchical menu of organizations the current user may switch to within the active tenant.

**Tags:** Directory

**Requires authentication.**

### Responses

**200** – Organization switcher payload.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "depth": 1,
      "selectable": true,
      "children": []
    }
  ],
  "selectedId": null,
  "canManage": true,
  "canViewAllOrganizations": true,
  "tenantId": null,
  "tenants": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true
    }
  ],
  "isSuperAdmin": true
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/directory/organization-switcher" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/directory/organizations`

Delete organization

Soft deletes an organization identified by id.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Organization deleted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/organizations`

List organizations

Returns organizations using options, tree, or paginated manage view depending on the `view` parameter.

Requires features: directory.organizations.view

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| view | query | any | Optional |
| ids | query | any | Optional |
| tenantId | query | any | Optional |
| includeInactive | query | any | Optional |
| status | query | any | Optional |

### Responses

**200** – Organization data for the requested view.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "parentId": null,
      "parentName": null,
      "tenantId": null,
      "tenantName": null,
      "rootId": null,
      "treePath": null
    }
  ]
}
```

**400** – Invalid query or tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/directory/organizations?page=1&pageSize=50&view=options" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/directory/organizations`

Create organization

Creates a new organization within a tenant and optionally assigns hierarchy relationships.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "slug": null,
  "logoUrl": null,
  "parentId": null
}
```

### Responses

**201** – Organization created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"slug\": null,
  \"logoUrl\": null,
  \"parentId\": null
}"
```

## PUT `/directory/organizations`

Update organization

Updates organization details and hierarchy assignments.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "slug": null,
  "logoUrl": null,
  "parentId": null
}
```

### Responses

**200** – Organization updated.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"slug\": null,
  \"logoUrl\": null,
  \"parentId\": null
}"
```

## GET `/directory/organizations/lookup`

Public organization lookup by slug

**Tags:** Directory (Tenants & Organizations)

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/directory/organizations/lookup" \
  -H "Accept: application/json"
```

## DELETE `/directory/tenants`

Delete tenant

Soft deletes the tenant identified by id.

Requires features: directory.tenants.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tenant removed.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/directory/tenants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/tenants`

List tenants

Returns tenants visible to the current user with optional search and pagination.

Requires features: directory.tenants.view

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| isActive | query | any | Optional |

### Responses

**200** – Paged list of tenants.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true,
      "createdAt": null,
      "updatedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/directory/tenants?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/directory/tenants`

Create tenant

Creates a new tenant and returns its identifier.

Requires features: directory.tenants.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string"
}
```

### Responses

**201** – Tenant created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/directory/tenants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\"
}"
```

## PUT `/directory/tenants`

Update tenant

Updates tenant properties such as name or activation state.

Requires features: directory.tenants.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tenant updated.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/directory/tenants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/tenants/lookup`

Public tenant lookup

**Tags:** Directory (Tenants & Organizations)

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/directory/tenants/lookup" \
  -H "Accept: application/json"
```

## GET `/dispatch/crew-specializations`

List crew specializations

Requires features: dispatch.view

**Tags:** Dispatch — Crew Specializations

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Paginated crew specializations

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "label": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/crew-specializations?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/crew-specializations`

Create a crew specialization

Requires features: dispatch.manage

**Tags:** Dispatch — Crew Specializations

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "label": "string"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/crew-specializations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"label\": \"string\"
}"
```

## DELETE `/dispatch/crew-specializations/{id}`

Soft delete a crew specialization no crew uses

Requires features: dispatch.manage

**Tags:** Dispatch — Crew Specializations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deleted

Content-Type: `application/json`

```json
{
  "deleted": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Still used by at least one crew

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dispatch/crew-specializations/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/crew-specializations/{id}`

Get a crew specialization

Requires features: dispatch.view

**Tags:** Dispatch — Crew Specializations

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Crew specialization

Content-Type: `application/json`

```json
{
  "id": "string",
  "label": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/crew-specializations/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/crew-specializations/{id}`

Update a crew specialization

Requires features: dispatch.manage

**Tags:** Dispatch — Crew Specializations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/crew-specializations/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## GET `/dispatch/crews`

List crews

Requires features: dispatch.view

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| specializations | query | any | Optional |
| statuses | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Paginated crews

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "specializationId": "string",
      "headCount": 1,
      "isActive": true,
      "status": "free"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/crews?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/crews`

Create a crew

Requires features: dispatch.manage

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "specializationId": "string",
  "headCount": 1
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/crews" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"specializationId\": \"string\",
  \"headCount\": 1
}"
```

## DELETE `/dispatch/crews/{id}`

Delete a crew that never had a reservation

Requires features: dispatch.manage

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deleted

Content-Type: `application/json`

```json
{
  "deleted": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Crew has reservation history

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dispatch/crews/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/crews/{id}`

Get a crew

Requires features: dispatch.view

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Crew detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "specializationId": "string",
  "headCount": 1,
  "isActive": true,
  "status": "free"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/crews/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/crews/{id}`

Update a crew

Requires features: dispatch.manage

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/crews/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## PUT `/dispatch/crews/{id}/reactivate`

Reactivate a crew (set active)

Requires features: dispatch.manage

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Reactivated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/crews/string/reactivate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/crews/{id}/retire`

Retire a crew (set inactive)

Requires features: dispatch.manage

**Tags:** Dispatch — Crews

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Retired

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/crews/string/retire" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/equipment`

List equipment

Requires features: dispatch.view

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| types | query | any | Optional |
| statuses | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Paginated equipment

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "resourceTypeId": "string",
      "sideNumber": "string",
      "isActive": true,
      "requiredPermit": "string",
      "status": "free"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/equipment?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/equipment`

Create equipment

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "type": "string",
  "sideNumber": "string"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/equipment" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"type\": \"string\",
  \"sideNumber\": \"string\"
}"
```

## GET `/dispatch/equipment-types`

List equipment types

Requires features: dispatch.view

**Tags:** Dispatch — Equipment Types

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Paginated equipment types

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "label": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/equipment-types?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/equipment-types`

Create an equipment type

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment Types

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "label": "string"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string",
  "label": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/equipment-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"label\": \"string\"
}"
```

## DELETE `/dispatch/equipment-types/{id}`

Delete an equipment type

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment Types

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deleted

Content-Type: `application/json`

```json
{
  "deleted": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dispatch/equipment-types/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/equipment-types/{id}`

Get an equipment type

Requires features: dispatch.view

**Tags:** Dispatch — Equipment Types

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Equipment type detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "label": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/equipment-types/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/equipment-types/{id}`

Update an equipment type

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment Types

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "label": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/equipment-types/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## DELETE `/dispatch/equipment/{id}`

Delete equipment that never had a reservation

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deleted

Content-Type: `application/json`

```json
{
  "deleted": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Equipment has reservation history

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/equipment/{id}`

Get equipment

Requires features: dispatch.view

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Equipment detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "resourceTypeId": "string",
  "sideNumber": "string",
  "isActive": true,
  "requiredPermit": "string",
  "status": "free"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/equipment/{id}`

Update equipment

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## PUT `/dispatch/equipment/{id}/reactivate`

Reactivate equipment

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Reactivated

Content-Type: `application/json`

```json
{
  "id": "string",
  "isActive": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/string/reactivate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/equipment/{id}/retire`

Retire equipment

Requires features: dispatch.manage

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Retired

Content-Type: `application/json`

```json
{
  "id": "string",
  "isActive": false
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/string/retire" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/equipment/attention`

Count of equipment requiring dispatcher attention

Requires features: dispatch.view

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.view

### Responses

**200** – Attention summary

Content-Type: `application/json`

```json
{
  "count": 1,
  "conflictSubjectCount": 1,
  "coverageGapReservationCount": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/attention" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/equipment/timeline`

Equipment timeline

Requires features: dispatch.view

**Tags:** Dispatch — Equipment

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| from | query | any | Required |
| to | query | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| types | query | any | Optional |
| statuses | query | any | Optional |
| jobSiteIds | query | any | Optional |

### Responses

**200** – Equipment timeline rows

Content-Type: `application/json`

```json
{
  "items": [
    {
      "equipment": {
        "id": "string",
        "name": "string",
        "resourceTypeId": "string",
        "sideNumber": "string",
        "isActive": true,
        "requiredPermit": "string",
        "status": "free"
      },
      "reservations": [
        {
          "id": "string",
          "tenantId": "string",
          "organizationId": "string",
          "jobSiteId": "string",
          "jobSiteName": "string",
          "subjectType": "equipment",
          "subjectId": "string",
          "subjectName": "string",
          "durationWorkingDays": 1,
          "latestStart": "string",
          "status": "planned"
        }
      ],
      "availabilityWindows": [
        {
          "id": "string",
          "resourceType": "equipment",
          "resourceId": "string",
          "startAt": "string",
          "endAt": "string",
          "reasonCode": "string"
        }
      ]
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/equipment/timeline?from=string&to=string&page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/executors`

List executors

Requires features: dispatch.view

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| specializations | query | any | Optional |
| statuses | query | any | Optional |

### Responses

**200** – Paginated executors

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "kind": "team",
      "refId": "string",
      "refName": "string",
      "availabilityRuleSetId": null,
      "specializationId": null,
      "isActive": true,
      "status": "free"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/executors?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/executors`

Create an executor

Requires features: dispatch.manage

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "kind": "team",
  "refId": "string",
  "availabilityRuleSetId": null
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string",
  "kind": "team",
  "refId": "string",
  "availabilityRuleSetId": "string",
  "isActive": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/executors" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"kind\": \"team\",
  \"refId\": \"string\",
  \"availabilityRuleSetId\": null
}"
```

## GET `/dispatch/executors/{id}`

Get an executor

Requires features: dispatch.view

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Executor detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "kind": "team",
  "refId": "string",
  "refName": "string",
  "availabilityRuleSetId": null,
  "specializationId": null,
  "isActive": true,
  "status": "free"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/executors/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/executors/{id}`

Update an executor

Requires features: dispatch.manage

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "availabilityRuleSetId": null
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "isActive": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/executors/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"availabilityRuleSetId\": null
}"
```

## PUT `/dispatch/executors/{id}/retire`

Retire an executor

Requires features: dispatch.manage

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Retired

Content-Type: `application/json`

```json
{
  "id": "string",
  "isActive": false
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/executors/string/retire" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/executors/attention`

Count of crews requiring dispatcher attention

Requires features: dispatch.view

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.view

### Responses

**200** – Attention summary

Content-Type: `application/json`

```json
{
  "count": 1,
  "conflictSubjectCount": 1,
  "coverageGapReservationCount": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/executors/attention" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/executors/timeline`

Executor timeline

Requires features: dispatch.view

**Tags:** Dispatch — Executors

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| from | query | any | Required |
| to | query | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| specializations | query | any | Optional |
| statuses | query | any | Optional |
| jobSiteIds | query | any | Optional |

### Responses

**200** – Executor timeline rows

Content-Type: `application/json`

```json
{
  "items": [
    {
      "executor": {
        "id": "string",
        "kind": "team",
        "refId": "string",
        "refName": "string",
        "availabilityRuleSetId": null,
        "specializationId": null,
        "isActive": true,
        "status": "free"
      },
      "reservations": [
        {
          "id": "string",
          "tenantId": "string",
          "organizationId": "string",
          "jobSiteId": "string",
          "jobSiteName": "string",
          "subjectType": "equipment",
          "subjectId": "string",
          "subjectName": "string",
          "durationWorkingDays": 1,
          "latestStart": "string",
          "status": "planned"
        }
      ],
      "availabilityWindows": [
        {
          "id": "string",
          "resourceType": "equipment",
          "resourceId": "string",
          "startAt": "string",
          "endAt": "string",
          "reasonCode": "string"
        }
      ]
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/executors/timeline?from=string&to=string&page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/job-sites`

List job sites

Requires features: dispatch.view

**Tags:** Dispatch — Job Sites

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| statuses | query | any | Optional |
| priorities | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Paginated job sites

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "color": "string",
      "statusEntryId": "string",
      "priorityEntryId": null,
      "jobSiteTypeEntryId": null,
      "periodStart": "string",
      "periodEnd": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/job-sites?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/job-sites`

Create a job site

Requires features: dispatch.manage

**Tags:** Dispatch — Job Sites

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "mode": "long",
  "location": {},
  "period": {
    "startDate": "string",
    "endDate": "string"
  },
  "statusEntryId": "string"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Domain rule violation (e.g. invalid_location)

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/job-sites" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"mode\": \"long\",
  \"location\": {},
  \"period\": {
    \"startDate\": \"string\",
    \"endDate\": \"string\"
  },
  \"statusEntryId\": \"string\"
}"
```

## DELETE `/dispatch/job-sites/{id}`

Delete a job site

Requires features: dispatch.manage

**Tags:** Dispatch — Job Sites

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deleted

Content-Type: `application/json`

```json
{
  "deleted": true
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/dispatch/job-sites/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dispatch/job-sites/{id}`

Get a job site

Requires features: dispatch.view

**Tags:** Dispatch — Job Sites

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Job site detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "mode": "long",
  "location": {},
  "period": {
    "startDate": "string",
    "endDate": "string"
  },
  "statusEntryId": "string",
  "priorityEntryId": null,
  "jobSiteTypeEntryId": null,
  "customerEntityId": null,
  "color": "string",
  "createdAt": "string",
  "updatedAt": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/job-sites/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/job-sites/{id}`

Update a job site

Requires features: dispatch.manage

**Tags:** Dispatch — Job Sites

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "priorityEntryId": null,
  "jobSiteTypeEntryId": null,
  "customerEntityId": null
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Domain rule violation (e.g. invalid_location)

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/job-sites/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"priorityEntryId\": null,
  \"jobSiteTypeEntryId\": null,
  \"customerEntityId\": null
}"
```

## GET `/dispatch/reservations`

List reservations

Requires features: dispatch.view

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| jobSiteId | query | any | Optional |
| subjectType | query | any | Optional |
| subjectId | query | any | Optional |
| status | query | any | Optional |
| types | query | any | Optional |
| specializations | query | any | Optional |

### Responses

**200** – Paginated reservations

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "tenantId": "string",
      "organizationId": "string",
      "jobSiteId": "string",
      "jobSiteName": "string",
      "subjectType": "equipment",
      "subjectId": "string",
      "subjectName": "string",
      "durationWorkingDays": 1,
      "latestStart": "string",
      "status": "planned"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/reservations?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/reservations`

Create a reservation

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "jobSiteId": "string",
  "subjectType": "equipment",
  "subjectId": "string",
  "durationWorkingDays": 1,
  "latestStart": "string"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string",
  "status": "planned"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/reservations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"jobSiteId\": \"string\",
  \"subjectType\": \"equipment\",
  \"subjectId\": \"string\",
  \"durationWorkingDays\": 1,
  \"latestStart\": \"string\"
}"
```

## GET `/dispatch/reservations/{id}`

Get a reservation

Requires features: dispatch.view

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Reservation detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "tenantId": "string",
  "organizationId": "string",
  "jobSiteId": "string",
  "jobSiteName": "string",
  "subjectType": "equipment",
  "subjectId": "string",
  "subjectName": "string",
  "durationWorkingDays": 1,
  "latestStart": "string",
  "status": "planned"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/reservations/{id}`

Update a reservation

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "note": null
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"note\": null
}"
```

## PUT `/dispatch/reservations/{id}/cancel`

Cancel a reservation

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Cancelled

Content-Type: `application/json`

```json
{
  "id": "string",
  "status": "cancelled"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Invalid transition

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dispatch/reservations/{id}/place`

Place a reservation on the timeline

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "startDate": "string"
}
```

### Responses

**200** – Placed

Content-Type: `application/json`

```json
{
  "id": "string",
  "placement": {
    "startAt": "string",
    "endAt": "string",
    "plannerRuleId": "string"
  },
  "status": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Conflict

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Invalid transition

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string/place" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"startDate\": \"string\"
}"
```

## PUT `/dispatch/reservations/{id}/status`

Change reservation status

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "status": "planned"
}
```

### Responses

**200** – Status changed

Content-Type: `application/json`

```json
{
  "id": "string",
  "status": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Invalid transition

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"status\": \"planned\"
}"
```

## POST `/dispatch/reservations/{id}/transfer`

Transfer a reservation to another job site

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "targetJobSiteId": "string",
  "startDate": "string"
}
```

### Responses

**201** – Transferred

Content-Type: `application/json`

```json
{
  "closedReservationId": "string",
  "newReservationId": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Conflict

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Invalid transition

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string/transfer" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"targetJobSiteId\": \"string\",
  \"startDate\": \"string\"
}"
```

## PUT `/dispatch/reservations/{id}/unplace`

Unplace a reservation (move it back to the backlog)

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Unplaced

Content-Type: `application/json`

```json
{
  "id": "string",
  "status": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Conflict

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Invalid transition

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/string/unplace" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dispatch/reservations/batch-apply`

Batch-apply timeline move/resize operations

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "operations": [
    {
      "reservationId": "string",
      "type": "move",
      "startAt": "string"
    }
  ]
}
```

### Responses

**200** – Applied

Content-Type: `application/json`

```json
{
  "results": [
    {
      "reservationId": "string",
      "status": "string"
    }
  ]
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**409** – Conflict

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

**422** – Invalid transition

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/batch-apply" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"operations\": [
    {
      \"reservationId\": \"string\",
      \"type\": \"move\",
      \"startAt\": \"string\"
    }
  ]
}"
```

## POST `/dispatch/reservations/schedule`

Create a reservation together with its placement (one transaction)

Requires features: dispatch.manage

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.manage

### Request Body

Content-Type: `application/json`

```json
{
  "jobSiteId": "string",
  "subjectType": "equipment",
  "subjectId": "string",
  "durationWorkingDays": 1,
  "latestStart": "string",
  "startDate": "string"
}
```

### Responses

**201** – Created and placed

Content-Type: `application/json`

```json
{
  "id": "string",
  "status": "string",
  "placement": {
    "startAt": "string",
    "endAt": "string",
    "plannerRuleId": null
  }
}
```

**404** – Job site or subject not found

Content-Type: `application/json`

```json
{
  "code": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/schedule" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"jobSiteId\": \"string\",
  \"subjectType\": \"equipment\",
  \"subjectId\": \"string\",
  \"durationWorkingDays\": 1,
  \"latestStart\": \"string\",
  \"startDate\": \"string\"
}"
```

## GET `/dispatch/reservations/unplaced`

List unplaced reservations

Requires features: dispatch.view

**Tags:** Dispatch — Reservations

**Requires authentication.**

**Features:** dispatch.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| subjectType | query | any | Optional |
| jobSiteIds | query | any | Optional |
| types | query | any | Optional |
| specializations | query | any | Optional |

### Responses

**200** – Paginated unplaced reservations

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "tenantId": "string",
      "organizationId": "string",
      "jobSiteId": "string",
      "jobSiteName": "string",
      "subjectType": "equipment",
      "subjectId": "string",
      "subjectName": "string",
      "durationWorkingDays": 1,
      "latestStart": "string",
      "status": "planned"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/dispatch/reservations/unplaced?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/entities/definitions`

Soft delete custom field definition

Marks the specified definition inactive and tombstones it for the current scope.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string"
}
```

### Responses

**200** – Definition deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id or key

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Definition not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/entities/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"key\": \"string\"
}"
```

## GET `/entities/definitions`

List active custom field definitions

Returns active custom field definitions for the supplied entity ids, respecting tenant scope and tombstones.

**Tags:** Entities

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Optional |
| entityIds | query | any | Optional |
| fieldset | query | any | Optional |

### Responses

**200** – Definition list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "key": "string",
      "kind": "string",
      "label": "string",
      "entityId": "string"
    }
  ]
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/definitions`

Upsert custom field definition

Creates or updates a custom field definition for the current tenant/org scope.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string",
  "kind": "text"
}
```

### Responses

**200** – Definition saved

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "key": "string",
    "kind": "string",
    "configJson": {}
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/entities/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"key\": \"string\",
  \"kind\": \"text\"
}"
```

## POST `/entities/definitions.batch`

Save multiple custom field definitions

Creates or updates multiple definitions for a single entity in one transaction.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "definitions": [
    {
      "key": "string",
      "kind": "text"
    }
  ]
}
```

### Responses

**200** – Definitions saved

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/entities/definitions.batch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"definitions\": [
    {
      \"key\": \"string\",
      \"kind\": \"text\"
    }
  ]
}"
```

## GET `/entities/definitions.manage`

Get management snapshot

Returns scoped custom field definitions (including inactive tombstones) for administration interfaces.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |

### Responses

**200** – Scoped definitions and deleted keys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "key": "string",
      "kind": "string",
      "configJson": null,
      "organizationId": null,
      "tenantId": null
    }
  ],
  "deletedKeys": [
    "string"
  ]
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/definitions.manage?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/definitions.restore`

Restore definition

Reactivates a previously soft-deleted definition within the current tenant/org scope.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string"
}
```

### Responses

**200** – Definition restored

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id or key

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Definition not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/entities/definitions.restore" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"key\": \"string\"
}"
```

## GET `/entities/encryption`

Fetch encryption map

Returns the encrypted field map for the current tenant/organization scope.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |

### Responses

**200** – Map

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "fields": [
    {
      "field": "string",
      "hashField": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/encryption?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/encryption`

Upsert encryption map

Creates or updates the encryption map for the current tenant/organization scope.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "tenantId": null,
  "organizationId": null,
  "fields": [
    {
      "field": "string",
      "hashField": null
    }
  ]
}
```

### Responses

**200** – Saved

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/entities/encryption" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"tenantId\": null,
  \"organizationId\": null,
  \"fields\": [
    {
      \"field\": \"string\",
      \"hashField\": null
    }
  ]
}"
```

## DELETE `/entities/entities`

Soft delete custom entity

Marks the specified custom entity inactive within the current scope.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string"
}
```

### Responses

**200** – Entity deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Entity not found in scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\"
}"
```

## GET `/entities/entities`

List available entities

Returns generated and custom entities scoped to the caller with field counts per entity.

**Tags:** Entities

**Requires authentication.**

### Responses

**200** – List of entities

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "source": "code",
      "label": "string",
      "count": 1
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/entities`

Upsert custom entity

Creates or updates a tenant/org scoped custom entity definition.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "label": "string",
  "description": null,
  "showInSidebar": false
}
```

### Responses

**200** – Entity saved

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "entityId": "string",
    "label": "string"
  }
}
```

**400** – Validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"label\": \"string\",
  \"description\": null,
  \"showInSidebar\": false
}"
```

## DELETE `/entities/records`

Delete record

Soft deletes the specified record within the current tenant/org scope.

Requires features: entities.records.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "recordId": "string"
}
```

### Responses

**200** – Record deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id or record id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Record not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/entities/records" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"recordId\": \"string\"
}"
```

## GET `/entities/records`

List records

Returns paginated records for the supplied entity. Supports custom field filters, exports, and soft-delete toggles.

Requires features: entities.records.view

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| format | query | any | Optional |
| exportScope | query | any | Optional |
| export_scope | query | any | Optional |
| all | query | any | Optional |
| full | query | any | Optional |

### Responses

**200** – Paginated records

Content-Type: `application/json`

```json
{
  "items": [
    {}
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/records?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/records`

Create record

Creates a record for the given entity. When `recordId` is omitted or not a UUID the data engine will generate one automatically.

Requires features: entities.records.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "values": {}
}
```

### Responses

**200** – Record created

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/entities/records" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"values\": {}
}"
```

## PUT `/entities/records`

Update record

Updates an existing record. If the provided recordId is not a UUID the record will be created instead to support optimistic flows.

Requires features: entities.records.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "recordId": "string",
  "values": {}
}
```

### Responses

**200** – Record updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/entities/records" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"recordId\": \"string\",
  \"values\": {}
}"
```

## GET `/entities/relations/options`

List relation options

Returns up to 200 option entries for populating relation dropdowns, automatically resolving label fields when omitted.

Requires features: entities.definitions.view

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |
| labelField | query | any | Optional |
| q | query | any | Optional |
| ids | query | any | Optional |
| routeContextFields | query | any | Optional |

### Responses

**200** – Option list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/relations/options?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/entities/sidebar-entities`

Get sidebar entities

Returns custom entities flagged with `showInSidebar` for the current tenant/org scope.

**Tags:** Entities

**Requires authentication.**

### Responses

**200** – Sidebar entities for navigation

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "label": "string",
      "href": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/entities/sidebar-entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/events`

List declared events

Returns every declared event. Filters: category, module, excludeTriggerExcluded (default true).

**Tags:** Events

**Requires authentication.**

### Responses

**200** – Declared events

Content-Type: `application/json`

```json
{
  "data": [
    {
      "id": "string",
      "label": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/events" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/events/stream`

GET /events/stream

**Tags:** Events

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/events/stream" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications`

List notifications

Returns a paginated collection of notifications.

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| status | query | any | Optional |
| type | query | any | Optional |
| severity | query | any | Optional |
| sourceEntityType | query | any | Optional |
| sourceEntityId | query | any | Optional |
| since | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated notifications

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "type": "string",
      "title": "string",
      "body": null,
      "titleKey": null,
      "bodyKey": null,
      "titleVariables": null,
      "bodyVariables": null,
      "icon": null,
      "severity": "string",
      "status": "string",
      "actions": [
        {
          "id": "string",
          "label": "string"
        }
      ],
      "sourceModule": null,
      "sourceEntityType": null,
      "sourceEntityId": null,
      "linkHref": null,
      "createdAt": "string",
      "readAt": null,
      "actionTaken": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/notifications?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications`

Create notification

Creates a notification for a user.

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Request Body

Content-Type: `application/json`

```json
{
  "type": "string",
  "severity": "info",
  "recipientUserId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Notification created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/notifications" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"type\": \"string\",
  \"severity\": \"info\",
  \"recipientUserId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/notifications/{id}/action`

POST /notifications/{id}/action

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/notifications/:id/action" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/{id}/dismiss`

PUT /notifications/{id}/dismiss

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/notifications/:id/dismiss" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/{id}/read`

PUT /notifications/{id}/read

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/notifications/:id/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/{id}/restore`

PUT /notifications/{id}/restore

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/notifications/:id/restore" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/batch`

POST /notifications/batch

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/notifications/batch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/feature`

POST /notifications/feature

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/notifications/feature" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/mark-all-read`

PUT /notifications/mark-all-read

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/notifications/mark-all-read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/role`

POST /notifications/role

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/notifications/role" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/settings`

GET /notifications/settings

Requires features: notifications.manage

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/notifications/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/settings`

POST /notifications/settings

Requires features: notifications.manage

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/notifications/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/unread-count`

GET /notifications/unread-count

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/notifications/unread-count" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/planner/availability`

Delete availability rule

Deletes an availability rule by id.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Availability rule deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/planner/availability" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/planner/availability`

List availability rules

Returns a paginated collection of availability rules scoped to the authenticated organization.

Requires features: planner.view

**Tags:** Planner

**Requires authentication.**

**Features:** planner.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| subjectType | query | any | Optional |
| subjectIds | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated availability rules

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "subject_type": null,
      "subject_id": null,
      "timezone": null,
      "rrule": null,
      "exdates": null,
      "kind": null,
      "note": null,
      "unavailability_reason_entry_id": null,
      "unavailability_reason_value": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/planner/availability?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/planner/availability`

Create availability rule

Creates an availability rule for the selected subject.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "subjectType": "member",
  "subjectId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "rrule": "string",
  "exdates": [],
  "kind": "availability",
  "note": null,
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null
}
```

### Responses

**201** – Availability rule created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/planner/availability" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"subjectType\": \"member\",
  \"subjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"rrule\": \"string\",
  \"exdates\": [],
  \"kind\": \"availability\",
  \"note\": null,
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null
}"
```

## PUT `/planner/availability`

Update availability rule

Updates an availability rule by id.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "note": null,
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null
}
```

### Responses

**200** – Availability rule updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/planner/availability" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"note\": null,
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null
}"
```

## POST `/planner/availability-date-specific`

Replace date-specific availability

Replaces date-specific availability rules for the subject in a single request.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "subjectType": "member",
  "subjectId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "windows": [],
  "isAvailable": true,
  "note": null,
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null
}
```

### Responses

**200** – Date-specific availability updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/planner/availability-date-specific" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"subjectType\": \"member\",
  \"subjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"windows\": [],
  \"isAvailable\": true,
  \"note\": null,
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null
}"
```

## DELETE `/planner/availability-rule-sets`

Delete availability rule set

Deletes an availability rule set by id.

Requires features: planner.manage_availability

**Tags:** Planner

**Requires authentication.**

**Features:** planner.manage_availability

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Availability rule set deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/planner/availability-rule-sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/planner/availability-rule-sets`

List availability rule sets

Returns a paginated collection of availability rule sets scoped to the authenticated organization.

Requires features: planner.view

**Tags:** Planner

**Requires authentication.**

**Features:** planner.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated availability rule sets

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "timezone": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/planner/availability-rule-sets?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/planner/availability-rule-sets`

Create availability rule set

Creates a reusable availability rule set.

Requires features: planner.manage_availability

**Tags:** Planner

**Requires authentication.**

**Features:** planner.manage_availability

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null,
  "timezone": "string"
}
```

### Responses

**201** – Availability rule set created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/planner/availability-rule-sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null,
  \"timezone\": \"string\"
}"
```

## PUT `/planner/availability-rule-sets`

Update availability rule set

Updates an availability rule set by id.

Requires features: planner.manage_availability

**Tags:** Planner

**Requires authentication.**

**Features:** planner.manage_availability

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null
}
```

### Responses

**200** – Availability rule set updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/planner/availability-rule-sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null
}"
```

## POST `/planner/availability-weekly`

Replace weekly availability

Replaces weekly availability rules for the subject in a single request.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "subjectType": "member",
  "subjectId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "windows": []
}
```

### Responses

**200** – Weekly availability updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/planner/availability-weekly" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"subjectType\": \"member\",
  \"subjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"windows\": []
}"
```

## POST `/query_index/purge`

Purge query index records

Queues a purge job to remove indexed records for an entity type within the active scope.

Requires features: query_index.purge

**Tags:** Query Index

**Requires authentication.**

**Features:** query_index.purge

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string"
}
```

### Responses

**200** – Purge job accepted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity type

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/query_index/purge" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\"
}"
```

## POST `/query_index/reindex`

Trigger query index rebuild

Queues a reindex job for the specified entity type within the current tenant scope.

Requires features: query_index.reindex

**Tags:** Query Index

**Requires authentication.**

**Features:** query_index.reindex

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string"
}
```

### Responses

**200** – Reindex job accepted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity type

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/query_index/reindex" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\"
}"
```

## GET `/query_index/status`

Inspect query index coverage

Returns entity counts comparing base tables with the query index along with the latest job status.

Requires features: query_index.status.view

**Tags:** Query Index

**Requires authentication.**

**Features:** query_index.status.view

### Responses

**200** – Current query index status.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "label": "string",
      "baseCount": null,
      "indexCount": null,
      "vectorCount": null,
      "ok": true,
      "job": {
        "status": "idle",
        "startedAt": null,
        "finishedAt": null,
        "heartbeatAt": null,
        "processedCount": null,
        "totalCount": null,
        "scope": null
      }
    }
  ],
  "errors": [
    {
      "id": "string",
      "source": "string",
      "handler": "string",
      "entityType": null,
      "recordId": null,
      "tenantId": null,
      "organizationId": null,
      "message": "string",
      "stack": null,
      "payload": null,
      "occurredAt": "string"
    }
  ],
  "logs": [
    {
      "id": "string",
      "source": "string",
      "handler": "string",
      "level": "info",
      "entityType": null,
      "recordId": null,
      "tenantId": null,
      "organizationId": null,
      "message": "string",
      "details": null,
      "occurredAt": "string"
    }
  ]
}
```

**400** – Tenant or organization context required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/query_index/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/resources/activities`

Delete resourceactivity

Deletes a resource activity.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – ResourceActivity deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/resources/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/activities`

List resourceactivitys

Returns a paginated collection of resourceactivitys scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated resourceactivitys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "resource_id": null,
      "activity_type": null,
      "subject": null,
      "body": null,
      "occurred_at": null,
      "author_user_id": null,
      "appearance_icon": null,
      "appearance_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/resources/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/activities`

Create resourceactivity

Adds an activity to a resource timeline.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "activityType": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – ResourceActivity created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"activityType\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/resources/activities`

Update resourceactivity

Updates a resource activity.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – ResourceActivity updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/resources/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/resources/comments`

Delete resourcecomment

Deletes a resource note.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – ResourceComment deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/resources/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/comments`

List resourcecomments

Returns a paginated collection of resourcecomments scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated resourcecomments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "resource_id": null,
      "body": null,
      "author_user_id": null,
      "appearance_icon": null,
      "appearance_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/resources/comments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/comments`

Create resourcecomment

Adds a note to a resource timeline.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – ResourceComment created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/resources/comments`

Update resourcecomment

Updates a resource note.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – ResourceComment updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/resources/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/resources/resource-types`

Delete resource type

Deletes a resource type by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Resource type deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/resources/resource-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/resource-types`

List resource types

Returns a paginated collection of resource types scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated resource types

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "appearance_icon": null,
      "appearance_color": null,
      "created_at": null,
      "updated_at": null,
      "resourceCount": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/resources/resource-types?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/resource-types`

Create resource type

Creates a resource type for resources resources.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Resource type created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/resource-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/resources/resource-types`

Update resource type

Updates a resource type by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Resource type updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/resources/resource-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/resources/resources`

Delete resource

Deletes a resource by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Resource deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/resources/resources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/resources`

List resources

Returns a paginated collection of resources scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| resourceTypeId | query | any | Optional |
| isActive | query | any | Optional |
| tagIds | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated resources

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "resource_type_id": null,
      "capacity": null,
      "capacity_unit_value": null,
      "capacity_unit_name": null,
      "capacity_unit_color": null,
      "capacity_unit_icon": null,
      "appearance_icon": null,
      "appearance_color": null,
      "is_active": null,
      "availability_rule_set_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/resources/resources?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/resources`

Create resource

Creates a resource scoped to the selected organization.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null,
  "resourceTypeId": null,
  "capacity": null,
  "capacityUnitValue": null,
  "appearanceIcon": null,
  "appearanceColor": null,
  "availabilityRuleSetId": null
}
```

### Responses

**201** – Resource created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/resources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null,
  \"resourceTypeId\": null,
  \"capacity\": null,
  \"capacityUnitValue\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null,
  \"availabilityRuleSetId\": null
}"
```

## PUT `/resources/resources`

Update resource

Updates a resource by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "resourceTypeId": null,
  "capacity": null,
  "capacityUnitValue": null,
  "appearanceIcon": null,
  "appearanceColor": null,
  "availabilityRuleSetId": null
}
```

### Responses

**200** – Resource updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/resources/resources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"resourceTypeId\": null,
  \"capacity\": null,
  \"capacityUnitValue\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null,
  \"availabilityRuleSetId\": null
}"
```

## POST `/resources/resources/tags/assign`

Assign resource tag

Assigns a tag to a resources resource.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "resourceId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Tag assignment created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/resources/tags/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"resourceId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/resources/resources/tags/unassign`

Unassign resource tag

Removes a tag from a resources resource.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "resourceId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tag assignment removed

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/resources/tags/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"resourceId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/resources/tags`

Delete resource tag

Deletes a resource tag by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Resource tag deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/resources/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/tags`

List resource tags

Returns a paginated collection of resource tags scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated resource tags

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "slug": null,
      "label": null,
      "color": null,
      "description": null,
      "organization_id": null,
      "tenant_id": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/resources/tags?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/tags`

Create resource tag

Creates a tag for resources resources and services.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "label": "string",
  "color": null,
  "description": null
}
```

### Responses

**201** – Resource tag created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/resources/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"label\": \"string\",
  \"color\": null,
  \"description\": null
}"
```

## PUT `/resources/tags`

Update resource tag

Updates a resource tag by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "color": null,
  "description": null
}
```

### Responses

**200** – Resource tag updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/resources/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"color\": null,
  \"description\": null
}"
```

## DELETE `/scheduler/jobs`

Delete scheduledjob

Deletes a scheduled job by ID.

Requires features: scheduler.jobs.manage

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – ScheduledJob deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/scheduler/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## GET `/scheduler/jobs`

List scheduledjobs

Returns a paginated collection of scheduledjobs scoped to the authenticated organization.

Requires features: scheduler.jobs.view

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| scopeType | query | any | Optional |
| isEnabled | query | any | Required |
| sourceType | query | any | Optional |
| sourceModule | query | any | Optional |
| sort | query | any | Optional |
| order | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated scheduledjobs

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "description": null,
      "scopeType": "system",
      "organizationId": null,
      "tenantId": null,
      "scheduleType": "cron",
      "scheduleValue": "string",
      "timezone": "string",
      "targetType": "queue",
      "targetQueue": null,
      "targetCommand": null,
      "targetPayload": null,
      "requireFeature": null,
      "isEnabled": true,
      "lastRunAt": null,
      "nextRunAt": null,
      "sourceType": "user",
      "sourceModule": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/scheduler/jobs?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/scheduler/jobs`

Create scheduledjob

Creates a new scheduled job with cron or interval-based scheduling.

Requires features: scheduler.jobs.manage

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "description": null,
  "scopeType": "system",
  "organizationId": null,
  "tenantId": null,
  "scheduleType": "cron",
  "scheduleValue": "string",
  "timezone": "UTC",
  "targetType": "queue",
  "targetQueue": null,
  "targetCommand": null,
  "targetPayload": null,
  "requireFeature": null,
  "isEnabled": true,
  "sourceType": "user",
  "sourceModule": null
}
```

### Responses

**201** – ScheduledJob created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/scheduler/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"description\": null,
  \"scopeType\": \"system\",
  \"organizationId\": null,
  \"tenantId\": null,
  \"scheduleType\": \"cron\",
  \"scheduleValue\": \"string\",
  \"timezone\": \"UTC\",
  \"targetType\": \"queue\",
  \"targetQueue\": null,
  \"targetCommand\": null,
  \"targetPayload\": null,
  \"requireFeature\": null,
  \"isEnabled\": true,
  \"sourceType\": \"user\",
  \"sourceModule\": null
}"
```

## PUT `/scheduler/jobs`

Update scheduledjob

Updates an existing scheduled job by ID.

Requires features: scheduler.jobs.manage

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "description": null,
  "targetQueue": null,
  "targetCommand": null,
  "targetPayload": null,
  "requireFeature": null
}
```

### Responses

**200** – ScheduledJob updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/scheduler/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"description\": null,
  \"targetQueue\": null,
  \"targetCommand\": null,
  \"targetPayload\": null,
  \"requireFeature\": null
}"
```

## GET `/scheduler/jobs/{id}/executions`

Get execution history for a schedule

Fetch recent executions from BullMQ for a scheduled job. Requires QUEUE_STRATEGY=async.

**Tags:** Scheduler

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| pageSize | query | any | Optional |

### Responses

**200** – Execution history

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "scheduleId": "00000000-0000-4000-8000-000000000000",
      "startedAt": "string",
      "finishedAt": null,
      "status": "running",
      "triggerType": "scheduled",
      "triggeredByUserId": null,
      "errorMessage": null,
      "errorStack": null,
      "durationMs": null,
      "queueJobId": "string",
      "queueName": "string",
      "attemptsMade": 1,
      "result": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1
}
```

**400** – Local strategy not supported

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Schedule not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/scheduler/jobs/:id/executions?pageSize=20" \
  -H "Accept: application/json"
```

## GET `/scheduler/queue-jobs/{jobId}`

Get BullMQ job details and logs

Fetch detailed information and logs for a queue job. Requires QUEUE_STRATEGY=async.

**Tags:** Scheduler

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| jobId | path | any | Required |
| queue | query | any | Required |

### Responses

**200** – Job details and logs

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "state": "waiting",
  "progress": null,
  "returnvalue": null,
  "failedReason": null,
  "stacktrace": null,
  "attemptsMade": 1,
  "processedOn": null,
  "finishedOn": null,
  "logs": [
    "string"
  ]
}
```

**400** – Invalid request or local strategy not supported

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Job not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Internal server error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/scheduler/queue-jobs/:jobId?queue=string" \
  -H "Accept: application/json"
```

## GET `/scheduler/targets`

List available queues and commands

Returns all registered queue names (from module workers) and command IDs (from the command registry) that can be used as schedule targets.

**Tags:** Scheduler

### Responses

**200** – Available targets

Content-Type: `application/json`

```json
{
  "queues": [
    {
      "value": "string",
      "label": "string"
    }
  ],
  "commands": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/scheduler/targets" \
  -H "Accept: application/json"
```

## POST `/scheduler/trigger`

Manually trigger a schedule

Executes a scheduled job immediately, bypassing the scheduled time. Only works with async queue strategy.

**Tags:** Scheduler

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – Schedule triggered successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "jobId": "string",
  "message": "string"
}
```

**400** – Invalid request or local strategy not supported

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Schedule not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/scheduler/trigger" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## DELETE `/staff/activities`

Delete teammemberactivity

Deletes a team member activity.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TeamMemberActivity deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/activities`

List teammemberactivitys

Returns a paginated collection of teammemberactivitys scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated teammemberactivitys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "activity_type": null,
      "subject": null,
      "body": null,
      "occurred_at": null,
      "author_user_id": null,
      "appearance_icon": null,
      "appearance_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/activities`

Create teammemberactivity

Adds an activity to a team member timeline.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "activityType": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – TeamMemberActivity created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"activityType\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/staff/activities`

Update teammemberactivity

Updates a team member activity.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – TeamMemberActivity updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/staff/addresses`

Delete teammemberaddress

Deletes a team member address.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TeamMemberAddress deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/addresses`

List teammemberaddresss

Returns a paginated collection of teammemberaddresss scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated teammemberaddresss

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "name": null,
      "purpose": null,
      "company_name": null,
      "address_line1": null,
      "address_line2": null,
      "building_number": null,
      "flat_number": null,
      "city": null,
      "region": null,
      "postal_code": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "is_primary": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/addresses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/addresses`

Create teammemberaddress

Adds a team member address.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "addressLine1": "string"
}
```

### Responses

**201** – TeamMemberAddress created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"addressLine1\": \"string\"
}"
```

## PUT `/staff/addresses`

Update teammemberaddress

Updates a team member address.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TeamMemberAddress updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/staff/comments`

Delete teammembercomment

Deletes a team member note.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TeamMemberComment deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/comments`

List teammembercomments

Returns a paginated collection of teammembercomments scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated teammembercomments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "body": null,
      "author_user_id": null,
      "appearance_icon": null,
      "appearance_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/comments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/comments`

Create teammembercomment

Adds a note to a team member timeline.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – TeamMemberComment created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/staff/comments`

Update teammembercomment

Updates a team member note.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – TeamMemberComment updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/staff/job-histories`

Delete teammemberjobhistory

Deletes a team member job history entry.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TeamMemberJobHistory deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/job-histories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/job-histories`

List teammemberjobhistorys

Returns a paginated collection of teammemberjobhistorys scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated teammemberjobhistorys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "name": null,
      "company_name": null,
      "description": null,
      "start_date": null,
      "end_date": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/job-histories?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/job-histories`

Create teammemberjobhistory

Adds a team member job history entry.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "companyName": null,
  "description": null,
  "startDate": "2025-01-01T00:00:00.000Z",
  "endDate": null
}
```

### Responses

**201** – TeamMemberJobHistory created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/job-histories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"companyName\": null,
  \"description\": null,
  \"startDate\": \"2025-01-01T00:00:00.000Z\",
  \"endDate\": null
}"
```

## PUT `/staff/job-histories`

Update teammemberjobhistory

Updates a team member job history entry.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "companyName": null,
  "description": null,
  "endDate": null
}
```

### Responses

**200** – TeamMemberJobHistory updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/job-histories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"companyName\": null,
  \"description\": null,
  \"endDate\": null
}"
```

## DELETE `/staff/leave-requests`

Delete leave request

Deletes a leave request by id.

**Tags:** Staff

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Leave request deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/leave-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/leave-requests`

List leave requests

Returns a paginated collection of leave requests scoped to the authenticated organization.

**Tags:** Staff

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| memberId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated leave requests

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "member_id": null,
      "start_date": null,
      "end_date": null,
      "timezone": null,
      "status": null,
      "unavailability_reason_entry_id": null,
      "unavailability_reason_value": null,
      "note": null,
      "decision_comment": null,
      "submitted_by_user_id": null,
      "decided_by_user_id": null,
      "decided_at": null,
      "created_at": null,
      "updated_at": null,
      "member": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/leave-requests?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/leave-requests`

Create leave request

Creates a leave request for a staff member.

**Tags:** Staff

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "memberId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "startDate": "2025-01-01T00:00:00.000Z",
  "endDate": "2025-01-01T00:00:00.000Z",
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null,
  "note": null,
  "submittedByUserId": null
}
```

### Responses

**201** – Leave request created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/leave-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"memberId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"startDate\": \"2025-01-01T00:00:00.000Z\",
  \"endDate\": \"2025-01-01T00:00:00.000Z\",
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null,
  \"note\": null,
  \"submittedByUserId\": null
}"
```

## PUT `/staff/leave-requests`

Update leave request

Updates a leave request by id.

**Tags:** Staff

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null,
  "note": null
}
```

### Responses

**200** – Leave request updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/leave-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null,
  \"note\": null
}"
```

## POST `/staff/leave-requests/accept`

Approve leave request

Approves a leave request and adds unavailability rules for the staff member.

Requires features: staff.leave_requests.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "decisionComment": null,
  "decidedByUserId": null
}
```

### Responses

**200** – Leave request approved

Content-Type: `application/json`

```json
{
  "ok": true,
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/leave-requests/accept" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"decisionComment\": null,
  \"decidedByUserId\": null
}"
```

## POST `/staff/leave-requests/reject`

Reject leave request

Rejects a leave request with an optional comment.

Requires features: staff.leave_requests.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "decisionComment": null,
  "decidedByUserId": null
}
```

### Responses

**200** – Leave request rejected

Content-Type: `application/json`

```json
{
  "ok": true,
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/leave-requests/reject" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"decisionComment\": null,
  \"decidedByUserId\": null
}"
```

## DELETE `/staff/team-members`

Delete team member

Deletes a team member by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Team member deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/team-members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/team-members`

List team members

Returns a paginated collection of team members scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| teamId | query | any | Optional |
| roleId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated team members

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "team_id": null,
      "display_name": null,
      "description": null,
      "user_id": null,
      "availability_rule_set_id": null,
      "is_active": null,
      "created_at": null,
      "updated_at": null,
      "user": null,
      "team": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/team-members?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/team-members`

Create team member

Creates a team member for staff assignments.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "displayName": "string",
  "description": null,
  "userId": null,
  "roleIds": [],
  "tags": [],
  "availabilityRuleSetId": null
}
```

### Responses

**201** – Team member created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/team-members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"displayName\": \"string\",
  \"description\": null,
  \"userId\": null,
  \"roleIds\": [],
  \"tags\": [],
  \"availabilityRuleSetId\": null
}"
```

## PUT `/staff/team-members`

Update team member

Updates a team member by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "description": null,
  "userId": null,
  "availabilityRuleSetId": null
}
```

### Responses

**200** – Team member updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "updatedAt": null
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/team-members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"description\": null,
  \"userId\": null,
  \"availabilityRuleSetId\": null
}"
```

## GET `/staff/team-members/assignable`

List staff members that can be assigned from customer flows

Returns active staff members linked to auth users. Access requires either customers.roles.manage or customers.activities.manage. Owned by the staff module; consumed from customer flows via this canonical URL. Replaces the deprecated /api/customers/assignable-staff route.

Requires features: customers.roles.view

**Tags:** Staff

**Requires authentication.**

**Features:** customers.roles.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Assignable staff members

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "teamMemberId": "00000000-0000-4000-8000-000000000000",
      "userId": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "email": null,
      "teamName": null,
      "user": null,
      "team": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/team-members/assignable?page=1&pageSize=24" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/staff/team-members/self`

Get current user team member profile

Returns the staff team member linked to the current user, if any.

Requires features: staff.leave_requests.send

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.send

### Responses

**200** – Team member profile

Content-Type: `application/json`

```json
{
  "member": null
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/team-members/self" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/team-members/self`

Create current user team member profile

Creates a team member profile for the signed-in user.

Requires features: staff.leave_requests.send

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.send

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "displayName": "string",
  "description": null
}
```

### Responses

**201** – Team member created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/team-members/self" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"displayName\": \"string\",
  \"description\": null
}"
```

## POST `/staff/team-members/tags/assign`

Assign team member tag

Assigns a tag to a staff team member.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "memberId": "00000000-0000-4000-8000-000000000000",
  "tag": "string"
}
```

### Responses

**201** – Tag assignment created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/team-members/tags/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"memberId\": \"00000000-0000-4000-8000-000000000000\",
  \"tag\": \"string\"
}"
```

## POST `/staff/team-members/tags/unassign`

Unassign team member tag

Removes a tag from a staff team member.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "memberId": "00000000-0000-4000-8000-000000000000",
  "tag": "string"
}
```

### Responses

**200** – Tag assignment removed

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/team-members/tags/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"memberId\": \"00000000-0000-4000-8000-000000000000\",
  \"tag\": \"string\"
}"
```

## DELETE `/staff/team-roles`

Delete team role

Deletes a team role by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Team role deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/team-roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/team-roles`

List team roles

Returns a paginated collection of team roles scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| teamId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated team roles

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "team_id": null,
      "name": null,
      "description": null,
      "appearance_icon": null,
      "appearance_color": null,
      "created_at": null,
      "updated_at": null,
      "team": null,
      "memberCount": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/team-roles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/team-roles`

Create team role

Creates a team role for staff team members.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "name": "string",
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Team role created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/team-roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"name\": \"string\",
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/staff/team-roles`

Update team role

Updates a team role by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Team role updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/team-roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/staff/teams`

Delete team

Deletes a staff team by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Team deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/teams" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/teams`

List teams

Returns a paginated collection of teams scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| isActive | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated teams

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "is_active": null,
      "created_at": null,
      "updated_at": null,
      "memberCount": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/teams?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/teams`

Create team

Creates a staff team.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null
}
```

### Responses

**201** – Team created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/teams" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null
}"
```

## PUT `/staff/teams`

Update team

Updates a staff team by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null
}
```

### Responses

**200** – Team updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/teams" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null
}"
```

## GET `/staff/timesheets/my-projects`

List assigned time project memberships for the current user

Returns staff_time_project_members where the authenticated user is an active member. Used by the My Timesheets grid to resolve assigned project IDs (spec N+1 mitigation query 1).

Requires features: staff.timesheets.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.view

### Responses

**200** – Assigned project memberships

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "time_project_id": "00000000-0000-4000-8000-000000000000",
      "staff_member_id": "00000000-0000-4000-8000-000000000000",
      "role": null,
      "status": null,
      "assigned_start_date": null,
      "assigned_end_date": null,
      "show_in_grid": true
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/timesheets/my-projects" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/staff/timesheets/my-projects/{projectId}`

Toggle grid visibility for one of the caller's assigned time projects

Self-service endpoint. Only the authenticated user can toggle `show_in_grid` on their own active membership for the given project. Does not require the admin-only `staff.timesheets.projects.manage` feature.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| projectId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "showInGrid": true
}
```

### Responses

**200** – Visibility updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "showInGrid": true
}
```

**400** – Invalid input

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Project membership not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://site-dispatch.dev.evojam.com/api/staff/timesheets/my-projects/:projectId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"showInGrid\": true
}"
```

## GET `/staff/timesheets/projects/kpis`

Aggregate KPIs for the timesheets Projects page

Returns a role-aware KPI payload. Users with `staff.timesheets.projects.manage` get the PM shape (portfolio totals, monthly team hours, active team member count). Other viewers get the Collaborator shape scoped to their own memberships and hours.

Requires features: staff.timesheets.projects.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.view

### Responses

**200** – PM or Collaborator KPIs

Content-Type: `application/json`

```json
{
  "role": "pm",
  "totals": {
    "total": 1,
    "active": 1,
    "onHold": 1,
    "completed": 1
  },
  "hoursWeek": {
    "current": 1,
    "previous": 1,
    "deltaPct": null
  },
  "hoursMonth": {
    "current": 1,
    "previous": 1,
    "deltaPct": null
  },
  "teamActive": {
    "count": 1
  },
  "assignedToMe": {
    "total": 1,
    "active": 1
  }
}
```

**500** – Aggregation failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/timesheets/projects/kpis" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/staff/timesheets/time-entries`

Delete timeentry

Deletes a time entry by id.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TimeEntry deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/timesheets/time-entries`

List timeentries

Returns a paginated collection of timeentries scoped to the authenticated organization.

Requires features: staff.timesheets.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| staffMemberId | query | any | Optional |
| from | query | any | Optional |
| to | query | any | Optional |
| projectId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated timeentries

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "staff_member_id": null,
      "date": null,
      "duration_minutes": null,
      "started_at": null,
      "ended_at": null,
      "notes": null,
      "time_project_id": null,
      "customer_id": null,
      "deal_id": null,
      "order_id": null,
      "source": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/timesheets/time-entries`

Create timeentry

Creates a time entry for a staff member.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "staffMemberId": "00000000-0000-4000-8000-000000000000",
  "date": "2025-01-01T00:00:00.000Z",
  "durationMinutes": 1,
  "startedAt": null,
  "endedAt": null,
  "timeProjectId": null,
  "customerId": null,
  "dealId": null,
  "orderId": null,
  "notes": null,
  "source": "manual"
}
```

### Responses

**201** – TimeEntry created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"staffMemberId\": \"00000000-0000-4000-8000-000000000000\",
  \"date\": \"2025-01-01T00:00:00.000Z\",
  \"durationMinutes\": 1,
  \"startedAt\": null,
  \"endedAt\": null,
  \"timeProjectId\": null,
  \"customerId\": null,
  \"dealId\": null,
  \"orderId\": null,
  \"notes\": null,
  \"source\": \"manual\"
}"
```

## PUT `/staff/timesheets/time-entries`

Update timeentry

Updates a time entry by id.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "timeProjectId": null,
  "customerId": null,
  "dealId": null,
  "orderId": null,
  "notes": null
}
```

### Responses

**200** – TimeEntry updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"timeProjectId\": null,
  \"customerId\": null,
  \"dealId\": null,
  \"orderId\": null,
  \"notes\": null
}"
```

## POST `/staff/timesheets/time-entries/{id}/segments`

Add a segment to a time entry

Creates a new work or break segment for the specified time entry.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "timeEntryId": "00000000-0000-4000-8000-000000000000",
  "startedAt": "2025-01-01T00:00:00.000Z",
  "endedAt": null,
  "segmentType": "work"
}
```

### Responses

**201** – Segment created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "timeEntryId": "00000000-0000-4000-8000-000000000000",
  "startedAt": "string",
  "endedAt": null,
  "segmentType": "work",
  "createdAt": "string"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Time entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries/:id/segments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"timeEntryId\": \"00000000-0000-4000-8000-000000000000\",
  \"startedAt\": \"2025-01-01T00:00:00.000Z\",
  \"endedAt\": null,
  \"segmentType\": \"work\"
}"
```

## PATCH `/staff/timesheets/time-entries/{id}/segments/{segmentId}`

Update a time entry segment

Updates fields on an existing time entry segment (startedAt, endedAt, segmentType).

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| segmentId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "endedAt": null
}
```

### Responses

**200** – Segment updated successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "string",
    "timeEntryId": "string",
    "startedAt": "string",
    "endedAt": null,
    "segmentType": "work",
    "createdAt": "string",
    "updatedAt": "string"
  }
}
```

**400** – Invalid payload or missing segment id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Segment not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries/:id/segments/:segmentId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"endedAt\": null
}"
```

## POST `/staff/timesheets/time-entries/{id}/timer-start`

Start timer for a time entry

Starts the timer on a time entry by setting startedAt and creating an initial work segment.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Timer started

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**404** – Time entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Timer already started, or another timer is already running for this staff member

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries/:id/timer-start" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/timesheets/time-entries/{id}/timer-stop`

Stop timer for a time entry

Stops the active timer segment, recalculates total work duration in minutes, and updates the time entry.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Timer stopped

Content-Type: `application/json`

```json
{
  "ok": true,
  "durationMinutes": 1
}
```

**404** – Time entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – No active timer segment

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries/:id/timer-stop" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/timesheets/time-entries/bulk`

Bulk save time entries

Creates, updates, or soft-deletes multiple time entries in a single request. Entries with durationMinutes=0 and an existing id are soft-deleted.

Requires features: staff.timesheets.manage_own

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.manage_own

### Request Body

Content-Type: `application/json`

```json
{
  "entries": [
    {
      "id": null,
      "date": "2025-01-01T00:00:00.000Z",
      "timeProjectId": "00000000-0000-4000-8000-000000000000",
      "durationMinutes": 1,
      "notes": null
    }
  ]
}
```

### Responses

**200** – Bulk save completed

Content-Type: `application/json`

```json
{
  "ok": true,
  "created": 1,
  "updated": 1,
  "deleted": 1
}
```

**422** – Validation error

Content-Type: `application/json`

```json
{
  "ok": false,
  "errors": [
    {
      "path": "string",
      "message": "string"
    }
  ]
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-entries/bulk" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entries\": [
    {
      \"id\": null,
      \"date\": \"2025-01-01T00:00:00.000Z\",
      \"timeProjectId\": \"00000000-0000-4000-8000-000000000000\",
      \"durationMinutes\": 1,
      \"notes\": null
    }
  ]
}"
```

## DELETE `/staff/timesheets/time-projects`

Delete timeproject

Soft-deletes a time project by id.

Requires features: staff.timesheets.projects.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TimeProject deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/timesheets/time-projects`

List time projects

Returns a paginated collection of time projects scoped to the authenticated organization.

Requires features: staff.timesheets.projects.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| q | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| projectType | query | any | Optional |
| status | query | any | Optional |
| customerId | query | any | Optional |
| mine | query | any | Optional |
| include | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated time projects

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "code": null,
      "description": null,
      "project_type": null,
      "color": null,
      "status": null,
      "customer_id": null,
      "owner_user_id": null,
      "cost_center": null,
      "start_date": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/timesheets/time-projects`

Create timeproject

Creates a time project.

Requires features: staff.timesheets.projects.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.manage

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "customerId": null,
  "code": "string",
  "description": null,
  "projectType": null,
  "color": null,
  "status": "active",
  "ownerUserId": null,
  "costCenter": null,
  "startDate": null
}
```

### Responses

**201** – TimeProject created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"customerId\": null,
  \"code\": \"string\",
  \"description\": null,
  \"projectType\": null,
  \"color\": null,
  \"status\": \"active\",
  \"ownerUserId\": null,
  \"costCenter\": null,
  \"startDate\": null
}"
```

## PUT `/staff/timesheets/time-projects`

Update timeproject

Updates a time project by id.

Requires features: staff.timesheets.projects.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "customerId": null,
  "description": null,
  "projectType": null,
  "color": null,
  "ownerUserId": null,
  "costCenter": null,
  "startDate": null
}
```

### Responses

**200** – TimeProject updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"customerId\": null,
  \"description\": null,
  \"projectType\": null,
  \"color\": null,
  \"ownerUserId\": null,
  \"costCenter\": null,
  \"startDate\": null
}"
```

## DELETE `/staff/timesheets/time-projects/{id}/employees`

Delete timeprojectmember

Unassigns an employee from a time project.

Requires features: staff.timesheets.projects.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – TimeProjectMember deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects/:id/employees" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/timesheets/time-projects/{id}/employees`

List time project members

Returns a paginated collection of time project members scoped to the authenticated organization.

Requires features: staff.timesheets.projects.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| timeProjectId | query | any | Optional |
| status | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated time project members

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "time_project_id": null,
      "staff_member_id": null,
      "role": null,
      "status": null,
      "assigned_start_date": null,
      "assigned_end_date": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects/:id/employees?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/timesheets/time-projects/{id}/employees`

Create timeprojectmember

Assigns an employee to a time project.

Requires features: staff.timesheets.projects.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.timesheets.projects.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "timeProjectId": "00000000-0000-4000-8000-000000000000",
  "staffMemberId": "00000000-0000-4000-8000-000000000000",
  "role": null,
  "status": "active",
  "assignedStartDate": "2025-01-01T00:00:00.000Z",
  "assignedEndDate": null
}
```

### Responses

**201** – TimeProjectMember created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://site-dispatch.dev.evojam.com/api/staff/timesheets/time-projects/:id/employees" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"timeProjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"staffMemberId\": \"00000000-0000-4000-8000-000000000000\",
  \"role\": null,
  \"status\": \"active\",
  \"assignedStartDate\": \"2025-01-01T00:00:00.000Z\",
  \"assignedEndDate\": null
}"
```

## GET `/version`

Deployed Open Mercato version

**Tags:** API Documentation

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://site-dispatch.dev.evojam.com/api/version" \
  -H "Accept: application/json"
```