# Open Mercato API

Version: 0.6.6

Auto-generated OpenAPI definition for all enabled modules.

## Servers
- https://portal.gt.freighttech.org/api – Default environment

## DELETE `/attachments`

Delete attachment

Removes an uploaded attachment and deletes the stored asset.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

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

### Responses

**200** – Attachment deleted

Content-Type: `application/json`

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

**400** – Missing attachment identifier

Content-Type: `application/json`

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

**404** – Attachment not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/attachments?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/attachments`

List attachments for a record

Returns uploaded attachments for the given entity record, ordered by newest first.

Requires features: attachments.view

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required. Entity identifier that owns the attachments |
| recordId | query | any | Required. Record identifier within the entity |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Attachments found for the record

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "url": "string",
      "fileName": "string",
      "fileSize": 1,
      "createdAt": "string",
      "mimeType": null,
      "content": null
    }
  ]
}
```

**400** – Missing entity or record identifiers

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/attachments?entityId=string&recordId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/attachments`

Upload attachment

Uploads a new attachment using multipart form-data and stores metadata for later retrieval.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Request Body

Content-Type: `multipart/form-data`

```text
entityId=string
recordId=string
file=string
```

### Responses

**200** – Attachment stored successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "string",
    "url": "string",
    "fileName": "string",
    "fileSize": 1,
    "content": null
  }
}
```

**400** – Payload validation error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: multipart/form-data" \
  -d "{
  \"entityId\": \"string\",
  \"recordId\": \"string\",
  \"file\": \"string\"
}"
```

## GET `/attachments/file/{id}`

Download or serve attachment file

Returns the raw file content for an attachment. Path parameter: {id} - Attachment UUID. Query parameter: ?download=1 - Force file download with Content-Disposition header. Access control is enforced based on partition settings.

**Tags:** Attachments

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

### Responses

**200** – File content with appropriate MIME type

Content-Type: `application/json`

**400** – Missing attachment ID

Content-Type: `application/json`

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

**401** – Unauthorized - authentication required for private partitions

Content-Type: `application/json`

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

**403** – Forbidden - insufficient permissions

Content-Type: `application/json`

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

**404** – Attachment or file not found

Content-Type: `application/json`

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

**500** – Partition misconfigured

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/attachments/file/:id" \
  -H "Accept: application/json"
```

## GET `/attachments/image/{id}/{slug}`

Serve image with optional resizing

Returns an image attachment with optional on-the-fly resizing and cropping. Resized images are cached for performance. Only works with image MIME types. Path parameter: {id} - Attachment UUID. Query parameters: ?width=N (1-4000 pixels), ?height=N (1-4000 pixels), ?cropType=cover|contain (resize behavior).

**Tags:** Attachments

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

### Responses

**200** – Binary image content (Content-Type: image/jpeg, image/png, etc.)

Content-Type: `application/json`

**400** – Invalid parameters, missing ID, or non-image attachment

Content-Type: `application/json`

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

**401** – Unauthorized - authentication required for private partitions

Content-Type: `application/json`

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

**403** – Forbidden - insufficient permissions

Content-Type: `application/json`

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

**404** – Image not found

Content-Type: `application/json`

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

**500** – Partition misconfigured or image rendering failed

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/attachments/image/:id/:slug" \
  -H "Accept: application/json"
```

## GET `/attachments/library`

List attachments

Returns paginated list of attachments with optional filtering by search term, partition, and tags. Includes available tags and partitions.

Requires features: attachments.view

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional. Page number for pagination |
| pageSize | query | any | Optional. Number of items per page (max 100) |
| search | query | any | Optional. Search by file name (case-insensitive) |
| partition | query | any | Optional. Filter by partition code |
| tags | query | any | Optional. Filter by tags (comma-separated) |
| sortField | query | any | Optional. Field to sort by |
| sortDir | query | any | Optional. Sort direction |

### Responses

**200** – Attachments list with pagination and metadata

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "fileName": "string",
      "fileSize": 1,
      "mimeType": "string",
      "partitionCode": "string",
      "partitionTitle": null,
      "url": null,
      "createdAt": "string",
      "tags": [
        "string"
      ],
      "assignments": [],
      "content": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "availableTags": [
    "string"
  ],
  "partitions": [
    {
      "code": "string",
      "title": "string",
      "description": null,
      "isPublic": true
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/attachments/library?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/attachments/library/{id}`

Delete attachment

Permanently deletes an attachment file from storage and database. Emits CRUD side effects.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

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

### Responses

**200** – Attachment deleted successfully

Content-Type: `application/json`

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

**400** – Invalid attachment ID

Content-Type: `application/json`

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

**404** – Attachment not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/attachments/library/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/attachments/library/{id}`

Get attachment details

Returns complete details of an attachment including metadata, tags, assignments, and custom fields.

Requires features: attachments.view

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.view

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

### Responses

**200** – Attachment details

Content-Type: `application/json`

```json
{
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "fileName": "string",
    "fileSize": 1,
    "mimeType": "string",
    "partitionCode": "string",
    "partitionTitle": null,
    "tags": [
      "string"
    ],
    "assignments": [],
    "content": null,
    "customFields": null
  }
}
```

**400** – Invalid attachment ID

Content-Type: `application/json`

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

**404** – Attachment not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/attachments/library/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/attachments/library/{id}`

Update attachment metadata

Updates attachment tags, assignments, and custom fields. Emits CRUD side effects for indexing and events.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Attachment updated successfully

Content-Type: `application/json`

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

**400** – Invalid payload or attachment ID

Content-Type: `application/json`

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

**404** – Attachment not found

Content-Type: `application/json`

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

**500** – Failed to save attributes

Content-Type: `application/json`

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

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/attachments/library/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/attachments/partitions`

Delete partition

Deletes a partition. Default partitions cannot be deleted. Partitions with existing attachments cannot be deleted.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Responses

**200** – Partition deleted successfully

Content-Type: `application/json`

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

**400** – Invalid ID or default partition deletion attempt

Content-Type: `application/json`

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

**404** – Partition not found

Content-Type: `application/json`

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

**409** – Partition in use

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/attachments/partitions`

List all attachment partitions

Returns all configured attachment partitions with storage settings, OCR configuration, and access control settings.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Responses

**200** – List of partitions

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "code": "string",
      "title": "string",
      "description": null,
      "isPublic": true,
      "requiresOcr": true,
      "ocrModel": null,
      "configJson": null,
      "createdAt": null,
      "updatedAt": null,
      "envKey": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/attachments/partitions`

Create new partition

Creates a new attachment partition with specified storage and OCR settings. Requires unique partition code.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "title": "string",
  "description": null,
  "ocrModel": null,
  "storageDriver": "local",
  "configJson": null
}
```

### Responses

**201** – Partition created successfully

Content-Type: `application/json`

```json
{
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "code": "string",
    "title": "string",
    "description": null,
    "isPublic": true,
    "requiresOcr": true,
    "ocrModel": null,
    "configJson": null,
    "createdAt": null,
    "updatedAt": null,
    "envKey": "string"
  }
}
```

**400** – Invalid payload or partition code

Content-Type: `application/json`

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

**409** – Partition code already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"title\": \"string\",
  \"description\": null,
  \"ocrModel\": null,
  \"storageDriver\": \"local\",
  \"configJson\": null
}"
```

## PUT `/attachments/partitions`

Update partition

Updates an existing partition. Partition code cannot be changed. Title, description, OCR settings, and access control can be modified.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "title": "string",
  "description": null,
  "ocrModel": null,
  "storageDriver": "local",
  "configJson": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Partition updated successfully

Content-Type: `application/json`

```json
{
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "code": "string",
    "title": "string",
    "description": null,
    "isPublic": true,
    "requiresOcr": true,
    "ocrModel": null,
    "configJson": null,
    "createdAt": null,
    "updatedAt": null,
    "envKey": "string"
  }
}
```

**400** – Invalid payload or code change attempt

Content-Type: `application/json`

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

**404** – Partition not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"title\": \"string\",
  \"description\": null,
  \"ocrModel\": null,
  \"storageDriver\": \"local\",
  \"configJson\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/attachments/transfer`

Transfer attachments to different record

Transfers one or more attachments from one record to another within the same entity type. Updates attachment assignments and metadata to reflect the new record.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "attachmentIds": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "toRecordId": "string"
}
```

### Responses

**200** – Attachments transferred successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "updated": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Attachments not found

Content-Type: `application/json`

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

**500** – Attachment model missing

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/attachments/transfer" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"attachmentIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ],
  \"toRecordId\": \"string\"
}"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/auth/admin/nav" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/autologin`

Auto sign-in using env-configured demo credentials

When OM_AUTOLOGIN_EMAIL / OM_AUTOLOGIN_PASSWORD are configured, signs the visitor in with those credentials and redirects into the app. Intended for single-tenant demo instances only. Falls back to the login page when disabled or misconfigured.

**Tags:** Authentication & Accounts

### Responses

**200** – Success response

Content-Type: `application/json`

**307** – Redirect into the app (or to /login on failure)

Content-Type: `text/html`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/auth/autologin" \
  -H "Accept: application/json"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/auth/roles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/roles`

Create role

Creates a new role anchored to the caller's tenant. Non-superadmins cannot target another tenant; supplying a foreign `tenantId` is rejected.

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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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. Pass scopeToActiveOrganization=1 to restrict results to the caller's active organization (used by recipient/assignee pickers so suggestions stay within the org that owns the resulting record).

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 |
| scopeToActiveOrganization | 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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\"
}"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/configs/cache" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"action\": \"purgeAll\"
}"
```

## DELETE `/configs/module-telemetry`

Clear module telemetry data

Development-only endpoint that clears in-memory module telemetry and local process telemetry files.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### Responses

**200** – Module telemetry cleared

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/configs/module-telemetry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/configs/module-telemetry`

Get module resource usage telemetry

Returns in-process module resource attribution for API routes, event subscribers, and queue workers.

Requires features: configs.system_status.view

**Tags:** Configs

**Requires authentication.**

**Features:** configs.system_status.view

### Responses

**200** – Module resource usage report

Content-Type: `application/json`

```json
{
  "generatedAt": "string",
  "startedAt": "string",
  "enabled": true,
  "bucketIntervalMs": 1,
  "totals": {
    "modules": 1,
    "operations": 1,
    "calls": 1,
    "errors": 1,
    "totalDurationMs": 1,
    "totalCpuMs": 1,
    "positiveHeapDeltaBytes": 1,
    "positiveRssDeltaBytes": 1
  },
  "thresholds": {
    "p95DurationMs": 1,
    "cpuMs": 1,
    "positiveHeapDeltaBytes": 1,
    "positiveRssDeltaBytes": 1,
    "errors": 1
  },
  "modules": [
    {
      "moduleId": "string",
      "calls": 1,
      "errors": 1,
      "totalDurationMs": 1,
      "p95DurationMs": 1,
      "totalCpuMs": 1,
      "positiveHeapDeltaBytes": 1,
      "positiveRssDeltaBytes": 1,
      "surfaces": [
        {
          "surface": "api",
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuMs": 1,
          "positiveHeapDeltaBytes": 1,
          "positiveRssDeltaBytes": 1
        }
      ],
      "topOperations": [
        {
          "moduleId": "string",
          "surface": "api",
          "operation": "string",
          "resourceId": null,
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "maxDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuUserMs": 1,
          "totalCpuSystemMs": 1,
          "maxCpuMs": 1,
          "totalHeapDeltaBytes": 1,
          "positiveHeapDeltaBytes": 1,
          "maxHeapDeltaBytes": 1,
          "totalRssDeltaBytes": 1,
          "positiveRssDeltaBytes": 1,
          "maxRssDeltaBytes": 1,
          "firstSeenAt": "string",
          "lastSeenAt": "string"
        }
      ],
      "candidateReasons": [
        "string"
      ]
    }
  ],
  "candidates": [
    {
      "moduleId": "string",
      "calls": 1,
      "errors": 1,
      "totalDurationMs": 1,
      "p95DurationMs": 1,
      "totalCpuMs": 1,
      "positiveHeapDeltaBytes": 1,
      "positiveRssDeltaBytes": 1,
      "surfaces": [
        {
          "surface": "api",
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuMs": 1,
          "positiveHeapDeltaBytes": 1,
          "positiveRssDeltaBytes": 1
        }
      ],
      "topOperations": [
        {
          "moduleId": "string",
          "surface": "api",
          "operation": "string",
          "resourceId": null,
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "maxDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuUserMs": 1,
          "totalCpuSystemMs": 1,
          "maxCpuMs": 1,
          "totalHeapDeltaBytes": 1,
          "positiveHeapDeltaBytes": 1,
          "maxHeapDeltaBytes": 1,
          "totalRssDeltaBytes": 1,
          "positiveRssDeltaBytes": 1,
          "maxRssDeltaBytes": 1,
          "firstSeenAt": "string",
          "lastSeenAt": "string"
        }
      ],
      "candidateReasons": [
        "string"
      ]
    }
  ],
  "buckets": [
    {
      "bucketStart": "string",
      "bucketEnd": "string",
      "bucketIntervalMs": 1,
      "stage": "startup",
      "partial": true,
      "totals": {
        "modules": 1,
        "calls": 1,
        "errors": 1,
        "totalDurationMs": 1,
        "totalCpuMs": 1,
        "positiveHeapDeltaBytes": 1,
        "positiveRssDeltaBytes": 1
      },
      "modules": [
        {
          "moduleId": "string",
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuMs": 1,
          "positiveHeapDeltaBytes": 1,
          "positiveRssDeltaBytes": 1,
          "surfaces": [
            {
              "surface": "api",
              "calls": 1,
              "errors": 1,
              "totalDurationMs": 1,
              "p95DurationMs": 1,
              "totalCpuMs": 1,
              "positiveHeapDeltaBytes": 1,
              "positiveRssDeltaBytes": 1
            }
          ],
          "topOperations": [
            {
              "moduleId": "string",
              "surface": "api",
              "operation": "string",
              "resourceId": null,
              "calls": 1,
              "errors": 1,
              "totalDurationMs": 1,
              "maxDurationMs": 1,
              "p95DurationMs": 1,
              "totalCpuUserMs": 1,
              "totalCpuSystemMs": 1,
              "maxCpuMs": 1,
              "totalHeapDeltaBytes": 1,
              "positiveHeapDeltaBytes": 1,
              "maxHeapDeltaBytes": 1,
              "totalRssDeltaBytes": 1,
              "positiveRssDeltaBytes": 1,
              "maxRssDeltaBytes": 1,
              "firstSeenAt": "string",
              "lastSeenAt": "string"
            }
          ],
          "candidateReasons": [
            "string"
          ]
        }
      ]
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/configs/module-telemetry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/configs/upgrade-actions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"actionId\": \"string\"
}"
```

## DELETE `/customer_accounts/admin/domain-mappings`

Remove a custom domain

Removes the domain mapping identified by ?id=. Cache and Traefik routing drain within TTL.

Requires features: customer_accounts.domain.manage

**Tags:** CustomerAccounts

**Requires authentication.**

**Features:** customer_accounts.domain.manage

### Responses

**200** – OK

Content-Type: `application/json`

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

**400** – Bad request

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customer_accounts/admin/domain-mappings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customer_accounts/admin/domain-mappings`

List domain mappings

Returns all custom-domain mappings for the current tenant, optionally filtered by organization.

Requires features: customer_accounts.domain.manage

**Tags:** CustomerAccounts

**Requires authentication.**

**Features:** customer_accounts.domain.manage

### Responses

**200** – OK

Content-Type: `application/json`

```json
{
  "ok": true,
  "domainMappings": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "hostname": "string",
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "provider": "traefik",
      "status": "pending",
      "verifiedAt": null,
      "lastDnsCheckAt": null,
      "dnsFailureReason": null,
      "tlsFailureReason": null,
      "tlsRetryCount": 1,
      "cnameTarget": null,
      "aRecordTarget": null,
      "createdAt": "string",
      "updatedAt": null
    }
  ],
  "config": {
    "cnameTarget": null,
    "aRecordTarget": null
  }
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/admin/domain-mappings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customer_accounts/admin/domain-mappings`

Register a custom domain

Registers a new custom domain mapping for an organization. Verifies via DNS asynchronously.

Requires features: customer_accounts.domain.manage

**Tags:** CustomerAccounts

**Requires authentication.**

**Features:** customer_accounts.domain.manage

### Request Body

Content-Type: `application/json`

```json
{
  "hostname": "string",
  "organizationId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "ok": true,
  "domainMapping": {
    "id": "00000000-0000-4000-8000-000000000000",
    "hostname": "string",
    "organizationId": "00000000-0000-4000-8000-000000000000",
    "tenantId": "00000000-0000-4000-8000-000000000000",
    "provider": "traefik",
    "status": "pending",
    "verifiedAt": null,
    "lastDnsCheckAt": null,
    "dnsFailureReason": null,
    "tlsFailureReason": null,
    "tlsRetryCount": 1,
    "cnameTarget": null,
    "aRecordTarget": null,
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**400** – Validation error

Content-Type: `application/json`

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

**409** – Conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/domain-mappings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"hostname\": \"string\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customer_accounts/admin/domain-mappings/{id}/health-check`

Trigger TLS health check

Runs an HTTPS probe to verify Traefik has provisioned a certificate. On success: transitions the mapping to active.

Requires features: customer_accounts.domain.manage

**Tags:** CustomerAccounts

**Requires authentication.**

**Features:** customer_accounts.domain.manage

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

### Responses

**200** – OK

Content-Type: `application/json`

```json
{
  "ok": true,
  "domainMapping": {
    "id": "00000000-0000-4000-8000-000000000000",
    "hostname": "string",
    "status": "string",
    "tlsRetryCount": 1,
    "tlsFailureReason": null
  }
}
```

**404** – Not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/domain-mappings/:id/health-check" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customer_accounts/admin/domain-mappings/{id}/verify`

Trigger DNS verification

Runs DNS verification (CNAME → A → reverse-resolve fallback) for the domain mapping. Returns diagnostics on failure.

Requires features: customer_accounts.domain.manage

**Tags:** CustomerAccounts

**Requires authentication.**

**Features:** customer_accounts.domain.manage

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

### Responses

**200** – OK — see status

Content-Type: `application/json`

```json
{
  "ok": true,
  "domainMapping": {
    "id": "00000000-0000-4000-8000-000000000000",
    "hostname": "string",
    "status": "string",
    "verifiedAt": null,
    "lastDnsCheckAt": null,
    "dnsFailureReason": null
  },
  "diagnostics": null
}
```

**404** – Not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/domain-mappings/:id/verify" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customer_accounts/admin/roles`

List customer roles (admin)

Returns all customer roles for the tenant.

**Tags:** Customer Accounts Admin

### Responses

**200** – Role list

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "slug": "string",
      "description": null,
      "isDefault": true,
      "isSystem": true,
      "customerAssignable": true,
      "createdAt": "string",
      "updatedAt": null
    }
  ],
  "total": 1,
  "totalPages": 1,
  "page": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/admin/roles" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/admin/roles`

Create customer role (admin)

Creates a new customer role with an empty ACL.

**Tags:** Customer Accounts Admin

### Request Body

Content-Type: `application/json`

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

### Responses

**201** – Role created

Content-Type: `application/json`

```json
{
  "ok": true,
  "role": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "slug": "string",
    "description": null,
    "isDefault": true,
    "isSystem": true,
    "customerAssignable": true,
    "createdAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**409** – Slug already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/roles" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"slug\": \"string\"
}"
```

## DELETE `/customer_accounts/admin/roles/{id}`

Delete customer role (admin)

Soft deletes a customer role and its ACL. The default role (auto-assigned to new portal users) and roles with assigned users cannot be deleted.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Role deleted

Content-Type: `application/json`

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

**400** – Default role or has assigned users

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/admin/roles/{id}`

Get customer role detail (admin)

Returns full customer role details including ACL features.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Role detail with ACL

Content-Type: `application/json`

```json
{
  "ok": true,
  "role": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "slug": "string",
    "description": null,
    "isDefault": true,
    "isSystem": true,
    "customerAssignable": true,
    "createdAt": "string",
    "updatedAt": null,
    "acl": {
      "features": [
        "string"
      ],
      "isPortalAdmin": true
    }
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/admin/roles/{id}`

Update customer role (admin)

Updates a customer role. System roles are protected from name changes.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Role updated

Content-Type: `application/json`

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

**400** – Validation failed or system role restriction

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## PUT `/customer_accounts/admin/roles/{id}/acl`

Update customer role ACL (admin)

Updates the ACL (features and portal admin flag) for a customer role. Invalidates RBAC cache after update.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – ACL updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

**409** – Stale ACL write (optimistic-lock conflict)

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000/acl" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"features\": [
    \"string\"
  ]
}"
```

## GET `/customer_accounts/admin/users`

List customer users (admin)

Returns a paginated list of customer users with roles. Supports filtering by status, company, role, and search.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Paginated user list

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "email": "string",
      "displayName": "string",
      "emailVerified": true,
      "isActive": true,
      "lockedUntil": null,
      "lastLoginAt": null,
      "customerEntityId": null,
      "personEntityId": null,
      "createdAt": "string",
      "updatedAt": null,
      "roles": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "name": "string",
          "slug": "string"
        }
      ]
    }
  ],
  "total": 1,
  "totalPages": 1,
  "page": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/admin/users" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/admin/users`

Create customer user (admin)

Creates a new customer user directly. Staff-initiated, bypasses signup flow.

**Tags:** Customer Accounts Admin

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string",
  "displayName": "string"
}
```

### Responses

**201** – User created

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**409** – Email already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/users" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\",
  \"displayName\": \"string\"
}"
```

## POST `/customer_accounts/admin/users-invite`

Invite customer user (admin)

Creates a staff-initiated invitation for a new customer user. The invitedByUserId is set from the staff auth context.

**Tags:** Customer Accounts Admin

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invitation created

Content-Type: `application/json`

```json
{
  "ok": true,
  "invitation": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "expiresAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**429** – Too many invitation requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/users-invite" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/customer_accounts/admin/users/{id}`

Delete customer user (admin)

Soft deletes a customer user and revokes all their active sessions.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – User deleted

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/admin/users/{id}`

Get customer user detail (admin)

Returns full customer user details including CRM links, roles, and active session count.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – User detail

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string",
    "emailVerified": true,
    "isActive": true,
    "lockedUntil": null,
    "lastLoginAt": null,
    "failedLoginAttempts": 1,
    "customerEntityId": null,
    "personEntityId": null,
    "createdAt": "string",
    "updatedAt": null,
    "roles": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "name": "string",
        "slug": "string"
      }
    ],
    "activeSessionCount": 1
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/admin/users/{id}`

Update customer user (admin)

Updates a customer user. Staff can update status, lock, CRM links, and roles. Role assignment bypasses customer_assignable check.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

```json
{
  "lockedUntil": null,
  "personEntityId": null,
  "customerEntityId": null
}
```

### Responses

**200** – User updated

Content-Type: `application/json`

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

**400** – Validation failed or role not found

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"lockedUntil\": null,
  \"personEntityId\": null,
  \"customerEntityId\": null
}"
```

## POST `/customer_accounts/admin/users/{id}/reset-password`

Reset customer user password (admin)

Allows staff to set a new password for a customer user.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

```json
{
  "newPassword": "string"
}
```

### Responses

**200** – Password reset

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000/reset-password" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"newPassword\": \"string\"
}"
```

## POST `/customer_accounts/admin/users/{id}/send-reset-link`

Send password reset link for customer user (admin)

Creates a password reset token for a customer user and returns a reset link URL. The admin must prepend the appropriate portal domain/slug to the relative URL.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Reset link generated

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000/send-reset-link" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/admin/users/{id}/verify-email`

Verify customer user email (admin)

Allows staff to manually mark a customer user email as verified.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Email verified

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000/verify-email" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/domain-check`

Verify a hostname is allowed for TLS provisioning

Called by Traefik before issuing a Let's Encrypt certificate. Requires the X-Domain-Check-Secret header to match DOMAIN_CHECK_SECRET.

**Tags:** CustomerAccounts

### Responses

**200** – Hostname allowed

Content-Type: `application/json`

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

**403** – Forbidden

Content-Type: `application/json`

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

**404** – Hostname not registered or not yet verified

Content-Type: `application/json`

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

**503** – Server misconfiguration

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/domain-check" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/domain-resolve`

Single-host resolve for the Node middleware

Internal endpoint used by the portal middleware to populate its in-memory cache. Requires X-Domain-Resolve-Secret header.

**Tags:** CustomerAccounts

### Responses

**200** – OK

Content-Type: `application/json`

```json
{
  "ok": true,
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "orgSlug": null,
  "status": "active"
}
```

**400** – Bad request

Content-Type: `application/json`

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

**403** – Forbidden

Content-Type: `application/json`

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

**404** – Not found

Content-Type: `application/json`

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

**503** – Server misconfiguration

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/domain-resolve" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/domain-resolve/all`

Batch warm-up for the Node middleware

Returns every active domain mapping in a single payload so the middleware can populate its cache on process start. Requires X-Domain-Resolve-Secret header.

**Tags:** CustomerAccounts

### Responses

**200** – OK

Content-Type: `application/json`

```json
{
  "ok": true,
  "domains": [
    {
      "hostname": "string",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "orgSlug": null,
      "status": "active"
    }
  ]
}
```

**403** – Forbidden

Content-Type: `application/json`

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

**429** – Too many requests

Content-Type: `application/json`

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

**503** – Server misconfiguration

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/domain-resolve/all" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/email/verify`

Verify customer email address

Validates the email verification token and marks the email as verified.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string"
}
```

### Responses

**200** – Email verified

Content-Type: `application/json`

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

**400** – Invalid or expired token

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/email/verify" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\"
}"
```

## POST `/customer_accounts/invitations/accept`

Accept customer invitation

Accepts an invitation, creates the user account, assigns roles, and auto-logs in.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string",
  "password": "string",
  "displayName": "string"
}
```

### Responses

**201** – Invitation accepted and user created

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  },
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Invalid or expired invitation

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/invitations/accept" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\",
  \"password\": \"string\",
  \"displayName\": \"string\"
}"
```

## POST `/customer_accounts/login`

Authenticate customer credentials

Validates customer credentials and issues JWT + session cookies.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string"
}
```

### Responses

**200** – Login successful

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  },
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Invalid credentials

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://portal.gt.freighttech.org/api/customer_accounts/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\"
}"
```

## POST `/customer_accounts/magic-link/request`

Request magic link login

Sends a magic link to the customer email. Always returns 200 to prevent enumeration.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Request accepted

Content-Type: `application/json`

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

**429** – Too many requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/magic-link/request" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\"
}"
```

## POST `/customer_accounts/magic-link/verify`

Verify magic link token

Validates the magic link token, auto-verifies email, and creates a session.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string"
}
```

### Responses

**200** – Login successful

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  },
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Invalid or expired token

Content-Type: `application/json`

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

**401** – Account not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/magic-link/verify" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\"
}"
```

## POST `/customer_accounts/password/reset-confirm`

Confirm customer password reset

Validates the reset token and sets a new password. Revokes all existing sessions.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string",
  "password": "string"
}
```

### Responses

**200** – Password reset successful

Content-Type: `application/json`

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

**400** – Invalid or expired token

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/password/reset-confirm" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\",
  \"password\": \"string\"
}"
```

## POST `/customer_accounts/password/reset-request`

Request customer password reset

Initiates a password reset flow. Always returns 200 to prevent email enumeration.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Request accepted

Content-Type: `application/json`

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

**429** – Too many requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/password/reset-request" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\"
}"
```

## GET `/customer_accounts/portal/events/stream`

Subscribe to portal events via SSE (Portal Event Bridge)

Long-lived SSE connection that receives server-side events marked with portalBroadcast: true. Events are filtered by the customer's tenant, organization, and recipient user audience.

**Tags:** Customer Portal

### Responses

**200** – Event stream (text/event-stream)

Content-Type: `application/json`

**401** – Not authenticated

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/events/stream" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/feature-check`

Check customer portal feature access

Checks which of the requested features the authenticated customer user has. Used by portal menu injection for feature-gating.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Feature check result

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/portal/feature-check" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"features\": [
    \"string\"
  ]
}"
```

## POST `/customer_accounts/portal/logout`

Customer logout

Revokes the current session and clears authentication cookies.

**Tags:** Customer Portal

### Responses

**200** – Logged out

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/portal/logout" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/nav`

Portal sidebar navigation

Returns the portal sidebar for the authenticated customer. Items are derived from each portal page's `nav` metadata and filtered by `requireCustomerFeatures` against the customer's grants (wildcards honored).

**Tags:** Customer Portal

### Responses

**200** – Portal sidebar groups

Content-Type: `application/json`

```json
{
  "ok": true,
  "orgSlug": "string",
  "groups": [
    {
      "id": "main",
      "items": [
        {
          "id": "string",
          "label": "string",
          "href": "string",
          "order": 1
        }
      ]
    }
  ],
  "grantedFeatures": [
    "string"
  ],
  "isPortalAdmin": true
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Organization not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/nav" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/notifications`

List customer notifications

Returns paginated notifications for the authenticated customer user. Dismissed notifications are excluded by default unless ?status=dismissed is specified.

**Tags:** Customer Portal

### Responses

**200** – Notification list

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "type": "string",
      "title": "string",
      "body": null,
      "titleKey": null,
      "bodyKey": null,
      "titleVariables": null,
      "bodyVariables": null,
      "icon": null,
      "severity": "info",
      "status": "unread",
      "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
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/notifications" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/notifications/{id}/dismiss`

Dismiss notification

Dismisses a single notification for the authenticated customer user.

**Tags:** Customer Portal

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

### Responses

**200** – Notification dismissed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Notification not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/portal/notifications/00000000-0000-4000-8000-000000000000/dismiss" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/notifications/{id}/read`

Mark notification as read

Marks a single notification as read for the authenticated customer user.

**Tags:** Customer Portal

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

### Responses

**200** – Notification marked as read

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Notification not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/portal/notifications/00000000-0000-4000-8000-000000000000/read" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/notifications/mark-all-read`

Mark all notifications as read

Marks all unread notifications as read for the authenticated customer user.

**Tags:** Customer Portal

### Responses

**200** – All notifications marked as read

Content-Type: `application/json`

```json
{
  "ok": true,
  "count": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/portal/notifications/mark-all-read" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/notifications/unread-count`

Get unread notification count

Returns the number of unread notifications for the authenticated customer user.

**Tags:** Customer Portal

### Responses

**200** – Unread count

Content-Type: `application/json`

```json
{
  "ok": true,
  "unreadCount": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/notifications/unread-count" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/password-change`

Change customer password

Changes the authenticated customer user password after verifying the current password. Revokes all existing sessions.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

```json
{
  "currentPassword": "string",
  "newPassword": "string"
}
```

### Responses

**200** – Password changed

Content-Type: `application/json`

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

**400** – Current password incorrect or validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/portal/password-change" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"currentPassword\": \"string\",
  \"newPassword\": \"string\"
}"
```

## GET `/customer_accounts/portal/profile`

Get customer profile

Returns the authenticated customer user profile with roles and permissions.

**Tags:** Customer Portal

### Responses

**200** – Profile data

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string",
    "emailVerified": true,
    "customerEntityId": null,
    "personEntityId": null,
    "isActive": true,
    "lastLoginAt": null,
    "createdAt": "string"
  },
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "slug": "string"
    }
  ],
  "resolvedFeatures": [
    "string"
  ],
  "isPortalAdmin": true
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/profile" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/profile`

Update customer profile

Updates the authenticated customer user profile.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Profile updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string"
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/portal/profile" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customer_accounts/portal/sessions`

List customer sessions

Returns active sessions for the authenticated customer user.

**Tags:** Customer Portal

### Responses

**200** – Session list

Content-Type: `application/json`

```json
{
  "ok": true,
  "sessions": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "ipAddress": null,
      "userAgent": null,
      "lastUsedAt": null,
      "createdAt": "string",
      "expiresAt": "string",
      "isCurrent": true
    }
  ]
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/sessions" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/sessions-refresh`

Refresh customer JWT from session token

Uses the session cookie to issue a fresh JWT access token.

**Tags:** Customer Portal

### Responses

**200** – Token refreshed

Content-Type: `application/json`

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

**401** – Invalid session

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/portal/sessions-refresh" \
  -H "Accept: application/json"
```

## DELETE `/customer_accounts/portal/sessions/{id}`

Revoke a customer session

Revokes a specific session (not the current one).

**Tags:** Customer Portal

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

### Responses

**200** – Session revoked

Content-Type: `application/json`

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

**400** – Cannot revoke current session

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Session not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customer_accounts/portal/sessions/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/users`

List company portal users

Lists portal users associated with the same company. Paginated (default pageSize 25, max 100).

**Tags:** Customer Portal

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

### Responses

**200** – Paginated user list

Content-Type: `application/json`

```json
{
  "ok": true,
  "users": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "email": "string",
      "displayName": "string",
      "emailVerified": true,
      "isActive": true,
      "lastLoginAt": null,
      "createdAt": "string",
      "roles": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "name": "string",
          "slug": "string"
        }
      ]
    }
  ],
  "total": 1,
  "totalPages": 1,
  "page": 1,
  "pageSize": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customer_accounts/portal/users" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/users-invite`

Invite a user to the company portal

Creates an invitation for a new user to join the company portal.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invitation created

Content-Type: `application/json`

```json
{
  "ok": true,
  "invitation": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "expiresAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions or non-assignable role

Content-Type: `application/json`

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

**429** – Too many invitation requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/portal/users-invite" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/customer_accounts/portal/users/{id}`

Delete a company portal user

Soft deletes a portal user and revokes all their sessions.

**Tags:** Customer Portal

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

### Responses

**200** – User deleted

Content-Type: `application/json`

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

**400** – Cannot delete self

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customer_accounts/portal/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/users/{id}/roles`

Update portal user roles

Assigns new roles to a company portal user.

**Tags:** Customer Portal

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

### Request Body

Content-Type: `application/json`

```json
{
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**200** – Roles updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customer_accounts/portal/users/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## POST `/customer_accounts/signup`

Register a new customer account

Accepts a signup request and always returns 202 to prevent account enumeration.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string",
  "displayName": "string"
}
```

### Responses

**202** – Signup accepted

Content-Type: `application/json`

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

**400** – Validation failed or invalid request origin

Content-Type: `application/json`

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

**429** – Too many signup attempts

Content-Type: `application/json`

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

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

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customer_accounts/signup" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\",
  \"displayName\": \"string\"
}"
```

## DELETE `/customers/activities`

Delete activity

DEPRECATED (sunset 2026-06-30): Deletes an activity. Use DELETE /api/customers/interactions instead.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Activity deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/activities`

List activitys

Returns a paginated collection of activitys scoped to the authenticated organization.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| dealId | query | any | Optional |
| activityType | 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 activitys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null,
      "entityId": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "dealId": null,
      "dealTitle": null,
      "customValues": null,
      "activityTypeLabel": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/activities`

Create activity

DEPRECATED (sunset 2026-06-30): Creates a timeline activity. Use POST /api/customers/interactions instead.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "00000000-0000-4000-8000-000000000000",
  "activityType": "string",
  "phoneNumber": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Activity created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"activityType\": \"string\",
  \"phoneNumber\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/customers/activities`

Update activity

DEPRECATED (sunset 2026-06-30): Updates an activity. Use PUT /api/customers/interactions instead.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "phoneNumber": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Activity updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"phoneNumber\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/customers/addresses`

Delete address

Deletes an address by id. The identifier may be included in the body or query.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Address deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/addresses`

List addresss

Returns a paginated collection of addresss scoped to the authenticated organization.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| id | 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 addresss

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entity_id": "00000000-0000-4000-8000-000000000000",
      "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,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/addresses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/addresses`

Create address

Creates a customer address record and associates it with the referenced entity.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "addressLine1": "string",
  "latitude": null,
  "longitude": null
}
```

### Responses

**201** – Address created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"addressLine1\": \"string\",
  \"latitude\": null,
  \"longitude\": null
}"
```

## PUT `/customers/addresses`

Update address

Updates fields on an existing customer address.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Address updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"latitude\": null,
  \"longitude\": null
}"
```

## GET `/customers/assignable-staff`

DEPRECATED: use GET /api/staff/team-members/assignable instead.

Deprecated. Returns 308 Permanent Redirect to /api/staff/team-members/assignable preserving the query string. Will be removed no earlier than the next major release.

Requires features: customers.roles.view

**Tags:** Customers

**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 (only reachable by following the redirect).

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
}
```

**308** – Permanent redirect to /api/staff/team-members/assignable.

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/assignable-staff?page=1&pageSize=24" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/comments`

Delete comment

Deletes a comment identified by `id` supplied via body or query string.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Comment deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/comments`

List comments

Returns a paginated collection of comments scoped to the authenticated organization.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| dealId | 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 comments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entity_id": null,
      "deal_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://portal.gt.freighttech.org/api/customers/comments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/comments`

Create comment

Adds a comment to a customer timeline.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Comment created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/customers/comments`

Update comment

Updates an existing timeline comment.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Comment updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/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 `/customers/companies`

Delete company

Deletes a company by id. The identifier can be provided via body or query.

Requires features: customers.companies.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Company deleted

Content-Type: `application/json`

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

**422** – Company has dependent records (people, deals, or direct staff); unlink or reassign before delete.

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "COMPANY_HAS_DEPENDENTS"
}
```

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/companies`

List companies

Returns a paginated collection of companies scoped to the authenticated organization.

Requires features: customers.companies.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| email | query | any | Optional |
| emailStartsWith | query | any | Optional |
| emailContains | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| status | query | any | Optional |
| lifecycleStage | query | any | Optional |
| source | query | any | Optional |
| hasEmail | query | any | Optional |
| hasPhone | query | any | Optional |
| hasNextInteraction | query | any | Optional |
| createdFrom | query | any | Optional |
| createdTo | query | any | Optional |
| id | query | any | Optional |
| tagIds | query | any | Optional |
| tagIdsEmpty | query | any | Optional |
| excludeIds | query | any | Optional |
| excludeLinkedPersonId | query | any | Optional |
| excludeLinkedCompanyId | query | any | Optional |
| excludeLinkedDealId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated companies

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "description": null,
      "owner_user_id": null,
      "primary_email": null,
      "primary_phone": null,
      "status": null,
      "lifecycle_stage": null,
      "source": null,
      "next_interaction_at": null,
      "next_interaction_name": null,
      "next_interaction_ref_id": null,
      "next_interaction_icon": null,
      "next_interaction_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/companies?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/companies`

Create company

Creates a company record and associated profile data.

Requires features: customers.companies.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "displayName": "string",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "legalName": null,
  "brandName": null,
  "domain": null,
  "websiteUrl": null,
  "sizeBucket": null,
  "annualRevenue": null
}
```

### Responses

**201** – Company created

Content-Type: `application/json`

```json
{
  "id": null,
  "companyId": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"displayName\": \"string\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"legalName\": null,
  \"brandName\": null,
  \"domain\": null,
  \"websiteUrl\": null,
  \"sizeBucket\": null,
  \"annualRevenue\": null
}"
```

## PUT `/customers/companies`

Update company

Updates company profile fields, tags, or custom attributes.

Requires features: customers.companies.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "legalName": null,
  "brandName": null,
  "domain": null,
  "websiteUrl": null,
  "sizeBucket": null,
  "annualRevenue": null
}
```

### Responses

**200** – Company updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"legalName\": null,
  \"brandName\": null,
  \"domain\": null,
  \"websiteUrl\": null,
  \"sizeBucket\": null,
  \"annualRevenue\": null
}"
```

## GET `/customers/companies/{id}`

Fetch company with related data

Returns a company customer record with optional related resources such as addresses, comments, activities, interactions, deals, todos, and linked people.

Requires features: customers.companies.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional. Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people). |

### Responses

**200** – Company detail payload

Content-Type: `application/json`

```json
{
  "interactionMode": "canonical",
  "company": {
    "id": "00000000-0000-4000-8000-000000000000",
    "displayName": null,
    "description": null,
    "ownerUserId": null,
    "primaryEmail": null,
    "primaryPhone": null,
    "status": null,
    "lifecycleStage": null,
    "source": null,
    "nextInteractionAt": null,
    "nextInteractionName": null,
    "nextInteractionRefId": null,
    "nextInteractionIcon": null,
    "nextInteractionColor": null,
    "organizationId": null,
    "tenantId": null,
    "temperature": null,
    "renewalQuarter": null,
    "createdAt": "string",
    "updatedAt": "string"
  },
  "profile": null,
  "customFields": {},
  "tags": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "color": null
    }
  ],
  "addresses": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": null,
      "purpose": null,
      "addressLine1": null,
      "addressLine2": null,
      "buildingNumber": null,
      "flatNumber": null,
      "city": null,
      "region": null,
      "postalCode": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "isPrimary": null,
      "createdAt": "string"
    }
  ],
  "comments": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "body": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "dealId": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "activities": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "dealId": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "interactions": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityId": null,
      "interactionType": "string",
      "title": null,
      "body": null,
      "status": "string",
      "scheduledAt": null,
      "occurredAt": null,
      "priority": null,
      "authorUserId": null,
      "ownerUserId": null,
      "dealId": null,
      "organizationId": null,
      "tenantId": null,
      "authorName": null,
      "authorEmail": null,
      "dealTitle": null,
      "customValues": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "source": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "deals": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "pipelineStage": null,
      "valueAmount": null,
      "valueCurrency": null,
      "probability": null,
      "expectedCloseAt": null,
      "ownerUserId": null,
      "source": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "todos": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "todoId": "00000000-0000-4000-8000-000000000000",
      "todoSource": "string",
      "createdAt": "string",
      "createdByUserId": null,
      "title": null,
      "isDone": null,
      "priority": null,
      "severity": null,
      "description": null,
      "dueAt": null,
      "todoOrganizationId": null,
      "customValues": null
    }
  ],
  "people": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": null,
      "primaryEmail": null,
      "primaryPhone": null,
      "status": null,
      "lifecycleStage": null,
      "jobTitle": null,
      "department": null,
      "createdAt": "string",
      "organizationId": null,
      "source": null,
      "temperature": null,
      "linkedAt": null
    }
  ],
  "viewer": {
    "userId": null,
    "name": null,
    "email": null
  }
}
```

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Company not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/companies/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/companies/{id}/people`

List linked people for a company

Requires features: customers.companies.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Paginated linked people

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "primaryEmail": null,
      "primaryPhone": null,
      "status": null,
      "lifecycleStage": null,
      "jobTitle": null,
      "department": null,
      "createdAt": "string",
      "organizationId": null,
      "temperature": null,
      "source": null,
      "linkedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/companies/:id/people?page=1&pageSize=20&sort=name-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/companies/{id}/roles`

Remove a company role assignment

Requires features: customers.roles.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.manage

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

### Responses

**200** – Role deleted

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/companies/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/companies/{id}/roles`

List roles for a company

Requires features: customers.roles.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.view

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

### Responses

**200** – Role assignments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityType": "company",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "userId": "00000000-0000-4000-8000-000000000000",
      "userName": null,
      "userEmail": null,
      "userPhone": null,
      "roleType": "string",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ]
}
```

**400** – Invalid request

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/companies/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/companies/{id}/roles`

Assign a role to a company

Requires features: customers.roles.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.manage

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

### Request Body

Content-Type: `application/json`

```json
{
  "roleType": "string",
  "userId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Role created

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**409** – Role already assigned

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/companies/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleType\": \"string\",
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/customers/companies/{id}/roles`

Update a company role assignment

Requires features: customers.roles.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.manage

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Role updated

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/companies/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/dashboard/widgets/customer-todos`

Fetch recent customer tasks

Returns the most recent customer tasks for display on dashboards, including legacy compatibility rows when needed.

Requires features: dashboards.view, customers.widgets.todos

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.todos

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

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "todoId": "00000000-0000-4000-8000-000000000000",
      "todoSource": "string",
      "todoTitle": null,
      "createdAt": "string",
      "organizationId": null,
      "entity": {
        "id": null,
        "displayName": null,
        "kind": null,
        "ownerUserId": null
      }
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dashboard/widgets/customer-todos?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dashboard/widgets/new-customers`

Fetch recently created customers

Returns the latest customers created within the scoped tenant/organization for dashboard display.

Requires features: dashboards.view, customers.widgets.new-customers

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.new-customers

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |
| kind | query | any | Optional |

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": null,
      "kind": null,
      "organizationId": null,
      "createdAt": "string",
      "ownerUserId": null
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dashboard/widgets/new-customers?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dashboard/widgets/new-deals`

Fetch recently created deals

Returns the latest deals created within the scoped tenant/organization for dashboard display.

Requires features: dashboards.view, customers.widgets.new-deals

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.new-deals

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

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "organizationId": null,
      "createdAt": "string",
      "ownerUserId": null,
      "valueAmount": null,
      "valueCurrency": null
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dashboard/widgets/new-deals?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dashboard/widgets/next-interactions`

Fetch upcoming customer interactions

Lists upcoming (or optionally past) customer interaction reminders ordered by interaction date.

Requires features: dashboards.view, customers.widgets.next-interactions

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.next-interactions

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |
| includePast | query | any | Optional |

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": null,
      "kind": null,
      "organizationId": null,
      "nextInteractionAt": null,
      "nextInteractionName": null,
      "nextInteractionIcon": null,
      "nextInteractionColor": null,
      "ownerUserId": null
    }
  ],
  "now": "string"
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dashboard/widgets/next-interactions?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/deals`

Delete deal

Deletes a deal by `id`. The identifier may be provided in the body or query parameters.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Deal deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/deals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/deals`

List deals

Returns a paginated collection of deals scoped to the authenticated organization.

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| pipelineStage | query | any | Optional |
| pipelineId | query | any | Optional |
| pipelineStageId | query | any | Optional |
| ownerUserId | query | any | Optional |
| expectedCloseAtFrom | query | any | Optional |
| expectedCloseAtTo | query | any | Optional |
| isStuck | query | any | Optional |
| isOverdue | query | any | Optional |
| needsAttention | query | any | Optional |
| valueCurrency | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| personEntityId | query | any | Optional. Deprecated; use personId |
| companyEntityId | query | any | Optional. Deprecated; use companyId |
| personId | query | any | Optional |
| companyId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated deals

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "description": null,
      "status": null,
      "pipeline_stage": null,
      "pipeline_id": null,
      "pipeline_stage_id": null,
      "value_amount": null,
      "value_currency": null,
      "probability": null,
      "expected_close_at": null,
      "owner_user_id": null,
      "source": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null,
      "organizationId": null,
      "tenantId": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/deals`

Create deal

Creates a sales deal, optionally associating people and companies.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**201** – Deal created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/deals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"title\": \"string\",
  \"ownerUserId\": null
}"
```

## PUT `/customers/deals`

Update deal

Updates pipeline position, metadata, or associations for an existing deal.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Deal updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/deals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"ownerUserId\": null
}"
```

## GET `/customers/deals/{id}`

Fetch deal with associations and pipeline context

Returns a deal with linked people, companies, closure fields, optional pipeline history, custom fields, and viewer context.

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

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

### Responses

**200** – Deal detail payload

Content-Type: `application/json`

```json
{
  "deal": {
    "id": "00000000-0000-4000-8000-000000000000",
    "title": null,
    "description": null,
    "status": null,
    "pipelineStage": null,
    "pipelineId": null,
    "pipelineStageId": null,
    "valueAmount": null,
    "valueCurrency": null,
    "probability": null,
    "expectedCloseAt": null,
    "ownerUserId": null,
    "source": null,
    "closureOutcome": null,
    "lossReasonId": null,
    "lossNotes": null,
    "organizationId": null,
    "tenantId": null,
    "createdAt": "string",
    "updatedAt": "string"
  },
  "people": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "person"
    }
  ],
  "companies": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "company"
    }
  ],
  "customFields": {},
  "viewer": {
    "userId": null,
    "name": null,
    "email": null
  },
  "pipelineStages": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "order": 1,
      "color": null,
      "icon": null
    }
  ],
  "stageTransitions": [
    {
      "stageId": "00000000-0000-4000-8000-000000000000",
      "stageLabel": "string",
      "stageOrder": 1,
      "transitionedAt": "string"
    }
  ],
  "owner": null
}
```

**404** – Deal not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/{id}/companies`

List linked companies for a deal

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Paginated linked companies

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "company",
      "linkedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/:id/companies?page=1&pageSize=20&sort=label-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/{id}/people`

List linked people for a deal

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Paginated linked people

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "person",
      "linkedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/:id/people?page=1&pageSize=20&sort=label-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/{id}/stats`

Fetch analytics for a closed deal

Returns week-to-date closure counts, sales cycle length, quarter ranking, and loss reason context for a closed deal.

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

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

### Responses

**200** – Deal closure stats payload

Content-Type: `application/json`

```json
{
  "dealValue": null,
  "dealCurrency": null,
  "closureOutcome": "won",
  "closedAt": "string",
  "pipelineName": null,
  "dealsClosedThisPeriod": 1,
  "salesCycleDays": null,
  "dealRankInQuarter": null,
  "lossReason": null
}
```

**400** – Deal is not closed

Content-Type: `application/json`

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

**404** – Deal not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/:id/stats" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/aggregate`

Per-stage counts and currency totals for kanban lane headers

Returns per-stage counts and totals for deals, with values converted to the tenant base currency where rates are available. Used to power kanban lane headers without loading every deal.

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| pipelineId | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| ownerUserId | query | any | Optional |
| personId | query | any | Optional |
| companyId | query | any | Optional |
| isStuck | query | any | Optional |
| isOverdue | query | any | Optional |
| expectedCloseAtFrom | query | any | Optional |
| expectedCloseAtTo | query | any | Optional |

### Responses

**200** – Per-stage aggregate payload

Content-Type: `application/json`

```json
{
  "baseCurrencyCode": null,
  "perStage": [
    {
      "stageId": "string",
      "count": 1,
      "openCount": 1,
      "totalInBaseCurrency": 1,
      "byCurrency": [
        {
          "currency": "string",
          "total": 1,
          "count": 1
        }
      ],
      "convertedAll": true,
      "missingRateCurrencies": [
        "string"
      ]
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/aggregate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/deals/bulk-update-owner`

Bulk reassign deal owner

Queues a background job that reassigns the listed deals to a new owner (or clears the owner when null).

Requires features: customers.deals.manage

**Tags:** Customer Relationship Management

**Requires authentication.**

**Features:** customers.deals.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/deals/bulk-update-owner" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/deals/bulk-update-stage`

Bulk update deal pipeline stage

Queues a background job that moves the listed deals to the same pipeline stage. Returns a progress job id to poll for completion.

Requires features: customers.deals.manage

**Tags:** Customer Relationship Management

**Requires authentication.**

**Features:** customers.deals.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/deals/bulk-update-stage" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/map`

Paginated deals that have a resolvable map location

Returns a page of deals that have a coordinate-bearing linked company/person address, each enriched with one resolved location (company primary first, then earliest created; person addresses as fallback). Deals with no coordinate-bearing address are excluded entirely, so every item carries a non-null location in normal operation; the schema keeps location nullable only for the rare case where the address is deleted between the located-deal resolution and the page fetch.

Requires features: customers.deals.view, customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view, customers.activities.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| pipelineStage | query | any | Optional |
| pipelineId | query | any | Optional |
| pipelineStageId | query | any | Optional |
| ownerUserId | query | any | Optional |
| expectedCloseAtFrom | query | any | Optional |
| expectedCloseAtTo | query | any | Optional |
| isStuck | query | any | Optional |
| isOverdue | query | any | Optional |
| needsAttention | query | any | Optional |
| valueCurrency | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| personEntityId | query | any | Optional. Deprecated; use personId |
| companyEntityId | query | any | Optional. Deprecated; use companyId |
| personId | query | any | Optional |
| companyId | query | any | Optional |

### Responses

**200** – Paged located deals

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "pipelineId": null,
      "pipelineStageId": null,
      "pipelineStage": null,
      "valueAmount": null,
      "valueCurrency": null,
      "probability": null,
      "expectedCloseAt": null,
      "ownerUserId": null,
      "updatedAt": null,
      "companies": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "label": null
        }
      ],
      "people": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "label": null
        }
      ],
      "location": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/map?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/summary`

Pipeline KPI metrics with period-over-period deltas for the deals list

Returns the four list-level KPI cards (pipeline value, active deals, won this quarter, win rate) with quarter-over-quarter deltas, per-stage open-pipeline breakdown, top owners, and a 6-month win-rate series. Values are converted to the tenant base currency where rates are available; partial conversions are disclosed via convertedAll/missingRateCurrencies.

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

### Responses

**200** – Deals KPI summary payload

Content-Type: `application/json`

```json
{
  "baseCurrencyCode": null,
  "convertedAll": true,
  "missingRateCurrencies": [
    "string"
  ],
  "pipelineValue": {
    "value": 1,
    "delta": {
      "value": 1,
      "direction": "up"
    },
    "stages": [
      {
        "stage": null,
        "count": 1,
        "value": 1
      }
    ]
  },
  "activeDeals": {
    "value": 1,
    "delta": {
      "value": 1,
      "direction": "up"
    },
    "ownersCount": 1,
    "needAttention": 1,
    "owners": [
      {
        "id": "string",
        "count": 1
      }
    ],
    "ownersOverflow": 1
  },
  "wonThisQuarter": {
    "value": 1,
    "delta": {
      "value": 1,
      "direction": "up"
    },
    "dealsClosed": 1,
    "avgDeal": 1
  },
  "winRate": {
    "value": 1,
    "deltaPp": 1,
    "direction": "up",
    "previousValue": 1,
    "series": [
      {
        "period": "string",
        "rate": 1
      }
    ]
  }
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/deals/summary" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dictionaries/{kind}`

List dictionary entries

Returns dictionary entries for the requested kind within the currently selected organization.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

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

### Responses

**200** – Dictionary entries

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null
    }
  ]
}
```

**400** – Failed to resolve dictionary context

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dictionaries/:kind" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/dictionaries/{kind}`

Create or override dictionary entry

Creates a dictionary entry (or updates the existing entry for the same value) within the current organization scope.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

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

### Request Body

Content-Type: `application/json`

```json
{
  "value": "string"
}
```

### Responses

**200** – Dictionary entry updated

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": null,
  "color": null,
  "icon": null,
  "organizationId": null
}
```

**201** – Dictionary entry created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": null,
  "color": null,
  "icon": null,
  "organizationId": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**409** – Duplicate value conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/dictionaries/:kind" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"value\": \"string\"
}"
```

## DELETE `/customers/dictionaries/{kind}/{id}`

Delete dictionary entry

Removes a customer dictionary entry by identifier.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

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

### Responses

**200** – Entry deleted

Content-Type: `application/json`

```json
{
  "success": true
}
```

**404** – Entry not found

Content-Type: `application/json`

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

**409** – Entry is in use and cannot be deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/dictionaries/:kind/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/dictionaries/{kind}/{id}`

Update dictionary entry

Updates value, label, color, or icon for an existing customer dictionary entry.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Updated dictionary entry

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": null,
  "color": null,
  "icon": null,
  "organizationId": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Entry not found

Content-Type: `application/json`

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

**409** – Duplicate value conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/customers/dictionaries/:kind/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customers/dictionaries/currency`

Resolve currency dictionary

Returns the active currency dictionary for the current organization scope, falling back to shared entries when required.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### Responses

**200** – Currency dictionary entries

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "entries": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null
    }
  ]
}
```

**404** – Currency dictionary missing

Content-Type: `application/json`

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

**500** – Unexpected error

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dictionaries/currency" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dictionaries/kind-settings`

List kind settings

Returns selection mode and visibility settings for each dictionary kind.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### Responses

**200** – Kind settings

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "kind": "string",
      "selectionMode": "single",
      "visibleInTags": true,
      "sortOrder": 1
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/dictionaries/kind-settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/dictionaries/kind-settings`

Update kind setting

Creates or updates settings for a specific dictionary kind.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "kind": "string"
}
```

### Responses

**200** – Setting updated

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "kind": "string",
  "selectionMode": "single",
  "visibleInTags": true,
  "sortOrder": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/customers/dictionaries/kind-settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"kind\": \"string\"
}"
```

## DELETE `/customers/interactions`

Delete interaction

Soft-deletes an interaction identified by `id`. Accepts id via body or query string.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Interaction deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/interactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/interactions`

List interactions

Returns a paginated collection of interactions scoped to the authenticated organization.

Requires features: customers.interactions.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| cursor | query | any | Optional |
| entityId | query | any | Optional |
| dealId | query | any | Optional |
| status | query | any | Optional |
| interactionType | query | any | Optional |
| type | query | any | Optional |
| excludeInteractionType | query | any | Optional |
| search | query | any | Optional |
| from | query | any | Optional |
| to | query | any | Optional |
| pinned | 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 interactions

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityId": null,
      "dealId": null,
      "interactionType": "string",
      "title": null,
      "body": null,
      "status": "string",
      "scheduledAt": null,
      "occurredAt": null,
      "priority": null,
      "authorUserId": null,
      "ownerUserId": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "source": null,
      "duration": null,
      "durationMinutes": null,
      "location": null,
      "allDay": null,
      "recurrenceRule": null,
      "recurrenceEnd": null,
      "participants": null,
      "reminderMinutes": null,
      "visibility": null,
      "linkedEntities": null,
      "guestPermissions": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": null,
      "updatedAt": null,
      "authorName": null,
      "authorEmail": null,
      "dealTitle": null,
      "customValues": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/interactions?limit=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/interactions`

Create interaction

Creates a new interaction linked to a customer entity or deal.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**201** – Interaction created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/interactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/customers/interactions`

Update interaction

Updates fields for an existing interaction.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**200** – Interaction updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/interactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/interactions/{id}/visibility`

Flip an email interaction visibility (private ↔ shared)

Requires features: customers.email.compose

**Tags:** Customers, Email

**Requires authentication.**

**Features:** customers.email.compose

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

### Responses

**200** – Updated

Content-Type: `application/json`

**400** – Invalid id

Content-Type: `application/json`

**404** – Email not found or not visible to caller

Content-Type: `application/json`

**422** – Invalid body

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/customers/interactions/:id/visibility" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/interactions/cancel`

Cancel an interaction

Marks an interaction as canceled.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Interaction canceled

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**404** – Interaction not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/interactions/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/interactions/complete`

Complete an interaction

Marks an interaction as done and sets occurredAt to current time (or a provided timestamp).

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Interaction completed

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**404** – Interaction not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/interactions/complete" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/interactions/conflicts`

Detect scheduling conflicts

Checks for overlapping planned interactions within the requested time window.

Requires features: customers.interactions.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| date | query | any | Required |
| startTime | query | any | Required |
| duration | query | any | Required |
| excludeId | query | any | Optional |
| userId | query | any | Optional |
| timezoneOffsetMinutes | query | any | Optional |

### Responses

**200** – Conflict detection result

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": {
    "hasConflicts": true,
    "conflicts": [
      {
        "id": "string",
        "title": null,
        "startTime": "string",
        "endTime": "string",
        "type": "string"
      }
    ]
  }
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/interactions/conflicts?date=string&startTime=string&duration=1" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/interactions/counts`

Get interaction counts by type

Returns per-type interaction counts scoped to an entity.

Requires features: customers.interactions.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.view

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

### Responses

**200** – Counts by interaction type

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": {
    "call": 1,
    "email": 1,
    "meeting": 1,
    "note": 1,
    "task": 1,
    "total": 1
  }
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/interactions/counts?entityId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/interactions/tasks`

List customertasks

Returns a paginated collection of customertasks scoped to the authenticated organization.

Requires features: customers.interactions.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| all | query | any | Optional |
| entityId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated customertasks

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "todoId": "string",
      "todoSource": "string",
      "todoTitle": null,
      "todoIsDone": null,
      "todoPriority": null,
      "todoSeverity": null,
      "todoDescription": null,
      "todoDueAt": null,
      "todoCustomValues": null,
      "todoOrganizationId": null,
      "organizationId": "string",
      "tenantId": "string",
      "createdAt": "string",
      "externalHref": null,
      "customer": {
        "id": null,
        "displayName": null,
        "kind": null
      }
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/interactions/tasks?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/labels`

List labels

Returns labels for the current user within the selected organization. Optionally includes assignment status for a specific entity.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### Responses

**200** – Labels list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "slug": "string",
      "label": "string"
    }
  ],
  "assignedIds": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/labels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/labels`

Create label

Creates a new label scoped to the current user and selected organization.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**201** – Label created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "slug": "string",
  "label": "string"
}
```

**409** – Duplicate slug

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/labels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"label\": \"string\"
}"
```

## POST `/customers/labels/assign`

Assign label

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "labelId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Already assigned

Content-Type: `application/json`

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

**201** – Assigned

Content-Type: `application/json`

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

**404** – Label or entity not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/labels/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"labelId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/labels/unassign`

Unassign label

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "labelId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Unassigned

Content-Type: `application/json`

```json
{
  "id": null
}
```

**404** – Label or entity not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/labels/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"labelId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/people`

Delete person

Deletes a person by id. Request body or query may provide the identifier.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Person deleted

Content-Type: `application/json`

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

**422** – Person has dependent records (e.g. linked deals); unlink or reassign before delete.

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "PERSON_HAS_DEPENDENTS"
}
```

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/people`

List people

Returns a paginated collection of people scoped to the authenticated organization.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| email | query | any | Optional |
| emailStartsWith | query | any | Optional |
| emailContains | query | any | Optional |
| status | query | any | Optional |
| lifecycleStage | query | any | Optional |
| source | query | any | Optional |
| hasEmail | query | any | Optional |
| hasPhone | query | any | Optional |
| hasNextInteraction | query | any | Optional |
| createdFrom | query | any | Optional |
| createdTo | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| id | query | any | Optional |
| tagIds | query | any | Optional |
| tagIdsEmpty | query | any | Optional |
| excludeIds | query | any | Optional |
| excludeLinkedCompanyId | query | any | Optional |
| excludeLinkedDealId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated people

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "description": null,
      "owner_user_id": null,
      "primary_email": null,
      "primary_phone": null,
      "status": null,
      "lifecycle_stage": null,
      "source": null,
      "next_interaction_at": null,
      "next_interaction_name": null,
      "next_interaction_ref_id": null,
      "next_interaction_icon": null,
      "next_interaction_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people`

Create person

Creates a person contact using scoped organization and tenant identifiers.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "firstName": "string",
  "lastName": "string",
  "linkedInUrl": null,
  "twitterUrl": null,
  "companyEntityId": null
}
```

### Responses

**201** – Person created

Content-Type: `application/json`

```json
{
  "id": null,
  "personId": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"firstName\": \"string\",
  \"lastName\": \"string\",
  \"linkedInUrl\": null,
  \"twitterUrl\": null,
  \"companyEntityId\": null
}"
```

## PUT `/customers/people`

Update person

Updates contact details or custom fields for a person.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "linkedInUrl": null,
  "twitterUrl": null,
  "companyEntityId": null
}
```

### Responses

**200** – Person updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"linkedInUrl\": null,
  \"twitterUrl\": null,
  \"companyEntityId\": null
}"
```

## GET `/customers/people/{id}`

Fetch person with related data

Returns a person customer record with optional related resources such as addresses, comments, activities, interactions, deals, and todos.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional. Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos). |

### Responses

**200** – Person detail payload

Content-Type: `application/json`

```json
{
  "interactionMode": "canonical",
  "person": {
    "id": "00000000-0000-4000-8000-000000000000",
    "displayName": null,
    "description": null,
    "ownerUserId": null,
    "primaryEmail": null,
    "primaryPhone": null,
    "status": null,
    "lifecycleStage": null,
    "source": null,
    "nextInteractionAt": null,
    "nextInteractionName": null,
    "nextInteractionRefId": null,
    "nextInteractionIcon": null,
    "nextInteractionColor": null,
    "organizationId": null,
    "tenantId": null,
    "createdAt": "string",
    "updatedAt": "string"
  },
  "profile": null,
  "customFields": {},
  "tags": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "color": null
    }
  ],
  "addresses": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": null,
      "purpose": null,
      "addressLine1": null,
      "addressLine2": null,
      "buildingNumber": null,
      "flatNumber": null,
      "city": null,
      "region": null,
      "postalCode": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "isPrimary": null,
      "createdAt": "string"
    }
  ],
  "comments": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "body": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "dealId": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "activities": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "dealId": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "interactions": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityId": null,
      "interactionType": "string",
      "title": null,
      "body": null,
      "status": "string",
      "scheduledAt": null,
      "occurredAt": null,
      "priority": null,
      "authorUserId": null,
      "ownerUserId": null,
      "dealId": null,
      "organizationId": null,
      "tenantId": null,
      "authorName": null,
      "authorEmail": null,
      "dealTitle": null,
      "customValues": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "source": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "deals": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "pipelineStage": null,
      "valueAmount": null,
      "valueCurrency": null,
      "probability": null,
      "expectedCloseAt": null,
      "ownerUserId": null,
      "source": null,
      "closureOutcome": null,
      "lossReasonId": null,
      "lossNotes": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "todos": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "todoId": "00000000-0000-4000-8000-000000000000",
      "todoSource": "string",
      "createdAt": "string",
      "createdByUserId": null,
      "title": null,
      "isDone": null,
      "priority": null,
      "severity": null,
      "description": null,
      "dueAt": null,
      "todoOrganizationId": null,
      "customValues": null
    }
  ],
  "isPrimary": true,
  "companies": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "isPrimary": true
    }
  ],
  "viewer": {
    "userId": null,
    "name": null,
    "email": null
  }
}
```

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Person not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/people/{id}/companies`

List linked companies for a person

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

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

### Responses

**200** – Linked company rows

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "companyId": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "isPrimary": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people/:id/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people/{id}/companies`

Link a company to a person

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Linked company row

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": {
    "id": "00000000-0000-4000-8000-000000000000",
    "companyId": "00000000-0000-4000-8000-000000000000",
    "displayName": "string",
    "isPrimary": true
  }
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/people/:id/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"companyId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/people/{id}/companies/{linkId}`

Remove a linked company from a person

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

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

### Responses

**200** – Deletion result

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/people/:id/companies/:linkId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/people/{id}/companies/{linkId}`

Update a linked company for a person

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Updated company link

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": null
}
```

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/customers/people/:id/companies/:linkId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customers/people/{id}/companies/enriched`

Get enriched company data for a person's linked companies

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Enriched company rows with profile, billing, tags, deals and more

Content-Type: `application/json`

```json
{
  "items": [
    {
      "linkId": "00000000-0000-4000-8000-000000000000",
      "companyId": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "isPrimary": true,
      "subtitle": null,
      "profile": null,
      "billing": null,
      "primaryAddress": null,
      "tags": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "label": "string",
          "color": null
        }
      ],
      "roles": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "roleValue": "string"
        }
      ],
      "activeDeal": null,
      "lastContactAt": null,
      "clv": null,
      "status": null,
      "lifecycleStage": null,
      "temperature": null,
      "renewalQuarter": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people/:id/companies/enriched?page=1&pageSize=20&sort=name-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/people/{id}/email-threads`

List a Person's email threads (Gmail-style conversation grouping)

Requires features: customers.people.view

**Tags:** Customers, Email

**Requires authentication.**

**Features:** customers.people.view

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

### Responses

**200** – Email threads for the person, grouped by conversation

Content-Type: `application/json`

**400** – Invalid person id

Content-Type: `application/json`

**404** – Person not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people/:id/email-threads" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people/{id}/emails`

Compose + send an email anchored to a Person

Requires features: customers.email.compose

**Tags:** Customers, Email

**Requires authentication.**

**Features:** customers.email.compose

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

### Responses

**200** – Email queued for send

Content-Type: `application/json`

**400** – Invalid person id

Content-Type: `application/json`

**404** – Person or channel not found

Content-Type: `application/json`

**409** – Channel not connected

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

**500** – Send failed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/people/:id/emails" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/people/{id}/roles`

Remove a person role assignment

Requires features: customers.roles.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.manage

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

### Responses

**200** – Role deleted

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/people/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/people/{id}/roles`

List roles for a person

Requires features: customers.roles.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.view

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

### Responses

**200** – Role assignments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityType": "company",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "userId": "00000000-0000-4000-8000-000000000000",
      "userName": null,
      "userEmail": null,
      "userPhone": null,
      "roleType": "string",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ]
}
```

**400** – Invalid request

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people/{id}/roles`

Assign a role to a person

Requires features: customers.roles.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.manage

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

### Request Body

Content-Type: `application/json`

```json
{
  "roleType": "string",
  "userId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Role created

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**409** – Role already assigned

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/people/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleType\": \"string\",
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/customers/people/{id}/roles`

Update a person role assignment

Requires features: customers.roles.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.roles.manage

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Role updated

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/people/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/people/check-phone`

Find person by phone digits

Performs an exact digits comparison (stripping non-numeric characters) to determine whether a customer contact matches the provided phone fragment.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

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

### Responses

**200** – Matching contact (if any)

Content-Type: `application/json`

```json
{
  "match": null
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/people/check-phone" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/pipeline-stages`

Delete pipeline stage

Deletes a pipeline stage. Returns 409 if active deals use this stage.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Stage deleted

Content-Type: `application/json`

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

**404** – Stage not found

Content-Type: `application/json`

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

**409** – Stage has active deals

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/pipeline-stages`

List pipeline stages

Returns pipeline stages for the authenticated organization, optionally filtered by pipelineId.

Requires features: customers.pipelines.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.view

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

### Responses

**200** – Stage list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "pipelineId": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "order": 1,
      "color": null,
      "icon": null,
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ],
  "total": 1
}
```

**400** – Invalid request

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/pipeline-stages`

Create pipeline stage

Creates a new pipeline stage.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "pipelineId": "00000000-0000-4000-8000-000000000000",
  "label": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Stage created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"pipelineId\": \"00000000-0000-4000-8000-000000000000\",
  \"label\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## PUT `/customers/pipeline-stages`

Update pipeline stage

Updates an existing pipeline stage.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Stage updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**404** – Stage not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"color\": null,
  \"icon\": null
}"
```

## POST `/customers/pipeline-stages/reorder`

Reorder pipeline stages

Updates the order of pipeline stages in bulk.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "stages": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order": 1
    }
  ]
}
```

### Responses

**200** – Stages reordered

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/pipeline-stages/reorder" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"stages\": [
    {
      \"id\": \"00000000-0000-4000-8000-000000000000\",
      \"order\": 1
    }
  ]
}"
```

## DELETE `/customers/pipelines`

Delete pipeline

Deletes a pipeline. Returns 409 if active deals exist.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Pipeline deleted

Content-Type: `application/json`

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

**404** – Pipeline not found

Content-Type: `application/json`

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

**409** – Pipeline has active deals

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/pipelines`

List pipelines

Returns a list of pipelines scoped to the authenticated organization.

Requires features: customers.pipelines.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.view

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

### Responses

**200** – Pipeline list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isDefault": true,
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ],
  "total": 1
}
```

**400** – Invalid request

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/pipelines`

Create pipeline

Creates a new pipeline within the authenticated organization.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**201** – Pipeline created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\"
}"
```

## PUT `/customers/pipelines`

Update pipeline

Updates an existing pipeline.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Pipeline updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**404** – Pipeline not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/settings/address-format`

Retrieve address format

Returns the current address formatting preference for the selected organization.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### Responses

**200** – Current address format

Content-Type: `application/json`

```json
{
  "addressFormat": "string"
}
```

**400** – Organization context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/settings/address-format" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/customers/settings/address-format`

Update address format

Updates the address format preference for the selected organization.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "addressFormat": "line_first"
}
```

### Responses

**200** – Updated address format

Content-Type: `application/json`

```json
{
  "addressFormat": "string"
}
```

**400** – Invalid payload or organization context

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/settings/address-format" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"addressFormat\": \"line_first\"
}"
```

## GET `/customers/settings/dictionary-sort-modes`

Retrieve dictionary sort modes

Returns entry sort preferences for customer dictionaries in the selected organization.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### Responses

**200** – Current dictionary sort modes

Content-Type: `application/json`

```json
{
  "dictionarySortModes": {
    "key": "label_asc"
  }
}
```

**400** – Organization context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/settings/dictionary-sort-modes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/settings/dictionary-sort-modes`

Update dictionary sort modes

Updates entry sort preferences for customer dictionaries in the selected organization.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "dictionarySortModes": {
    "key": "label_asc"
  }
}
```

### Responses

**200** – Updated dictionary sort modes

Content-Type: `application/json`

```json
{
  "dictionarySortModes": {
    "key": "label_asc"
  }
}
```

**400** – Invalid payload or organization context

Content-Type: `application/json`

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

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/customers/settings/dictionary-sort-modes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"dictionarySortModes\": {
    \"key\": \"label_asc\"
  }
}"
```

## GET `/customers/settings/stuck-threshold`

Retrieve stuck-threshold days

Returns the current stuck-deal threshold (in days) for the selected organization.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Responses

**200** – Current threshold

Content-Type: `application/json`

```json
{
  "stuckThresholdDays": 1
}
```

**400** – Organization context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/settings/stuck-threshold" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/customers/settings/stuck-threshold`

Update stuck-threshold days

Updates the stuck-deal threshold for the selected organization.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "stuckThresholdDays": 1
}
```

### Responses

**200** – Updated threshold

Content-Type: `application/json`

```json
{
  "stuckThresholdDays": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/settings/stuck-threshold" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"stuckThresholdDays\": 1
}"
```

## DELETE `/customers/tags`

Delete tag

Deletes a tag identified by `id`. The identifier may be provided via body or query string.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Tag deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/tags`

List tags

Returns a paginated collection of tags scoped to the authenticated organization.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.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 tags

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "slug": "string",
      "label": "string",
      "color": null,
      "description": null,
      "organization_id": null,
      "tenant_id": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/tags?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/tags`

Create tag

Creates a tag scoped to the current tenant and organization.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "slug": "string",
  "label": "string"
}
```

### Responses

**201** – Tag created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"slug\": \"string\",
  \"label\": \"string\"
}"
```

## PUT `/customers/tags`

Update tag

Updates label, color, or description for an existing tag.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Tag updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/tags/assign`

Assign tag to customer entity

Links a tag to a customer entity within the validated tenant / organization scope.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Tag assigned to customer

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation or assignment failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/tags/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/tags/unassign`

Remove tag from customer entity

Detaches a tag from a customer entity within the validated tenant / organization scope.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tag unassigned from customer

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation or unassignment failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/tags/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/todos`

Delete customertodo

DEPRECATED (sunset 2026-06-30): Deletes a customer task. Use DELETE /api/customers/interactions instead.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – CustomerTodo deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/customers/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/todos`

List customertodos

Returns a paginated collection of customertodos scoped to the authenticated organization.

Requires features: customers.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| all | query | any | Optional |
| entityId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated customertodos

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "todoId": "string",
      "todoSource": "string",
      "todoTitle": null,
      "todoIsDone": null,
      "todoPriority": null,
      "todoSeverity": null,
      "todoDescription": null,
      "todoDueAt": null,
      "todoCustomValues": null,
      "todoOrganizationId": null,
      "todoUpdatedAt": null,
      "organizationId": "string",
      "tenantId": "string",
      "createdAt": "string",
      "externalHref": null,
      "customer": {
        "id": null,
        "displayName": null,
        "kind": null
      }
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/customers/todos?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/todos`

Create customertodo

DEPRECATED (sunset 2026-06-30): Creates a customer task. Use POST /api/customers/interactions instead.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "00000000-0000-4000-8000-000000000000",
  "title": "string",
  "todoSource": "customers:interaction"
}
```

### Responses

**201** – CustomerTodo created

Content-Type: `application/json`

```json
{
  "linkId": null,
  "todoId": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/customers/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"title\": \"string\",
  \"todoSource\": \"customers:interaction\"
}"
```

## PUT `/customers/todos`

Update customertodo

DEPRECATED (sunset 2026-06-30): Updates a customer task. Use PUT /api/customers/interactions instead.

Requires features: customers.interactions.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.interactions.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – CustomerTodo updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/customers/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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,
  "updatedAt": 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://portal.gt.freighttech.org/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,
  "updatedAt": null
}
```

**400** – Save failed

Content-Type: `application/json`

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

**409** – Organization branding changed since it was loaded

Content-Type: `application/json`

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

**422** – Invalid logo URL

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/directory/tenants/lookup" \
  -H "Accept: application/json"
```

## 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,
  "version": null
}
```

**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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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,
  "version": null
}
```

**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://portal.gt.freighttech.org/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"
  ],
  "version": null
}
```

**400** – Missing entity id

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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
    }
  ],
  "updatedAt": null
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/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. Enforces optimistic locking when the caller sends the expected version header.

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,
  "updatedAt": null
}
```

**409** – Optimistic-lock conflict (stale write)

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "string",
  "currentUpdatedAt": "string",
  "expectedUpdatedAt": "string"
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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
}"
```

## GET `/entities/filter-suggestions`

Get filter suggestions for a field

Returns distinct values for a specific field from any entity. Used by DynamicTable filter popover to provide autocomplete suggestions for large datasets.

**Tags:** Entities

**Requires authentication.**

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

### Responses

**200** – List of unique values for the field

Content-Type: `application/json`

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

**400** – Invalid parameters

Content-Type: `application/json`

```json
{
  "error": "string",
  "items": [
    "string"
  ]
}
```

**500** – Server error

Content-Type: `application/json`

```json
{
  "error": "string",
  "items": [
    "string"
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/entities/filter-suggestions?entityId=string&field=string&query=&limit=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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://portal.gt.freighttech.org/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 |
| search | query | any | Optional |
| searchFields | 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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).

Requires features: workflows.view

**Tags:** Events

**Requires authentication.**

**Features:** workflows.view

### Responses

**200** – Declared events

Content-Type: `application/json`

```json
{
  "data": [
    {
      "id": "string",
      "label": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/events/stream" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/boolean`

Check if feature is enabled

Checks if a feature toggle is enabled for the current context.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – Feature status

Content-Type: `application/json`

```json
{
  "enabled": true,
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

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

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/check/boolean?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/json`

Get json config

Gets the json configuration for a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – Json config

Content-Type: `application/json`

```json
{
  "valueType": "json",
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

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

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/check/json?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/number`

Get number config

Gets the number configuration for a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – Number config

Content-Type: `application/json`

```json
{
  "valueType": "number",
  "value": 1,
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

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

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/check/number?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/string`

Get string config

Gets the string configuration for a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – String config

Content-Type: `application/json`

```json
{
  "valueType": "string",
  "value": "string",
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

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

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/check/string?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/feature_toggles/global`

Delete global feature toggle

Soft deletes a global feature toggle by ID. Requires superadmin role.

Requires features: feature_toggles.global.manage

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.global.manage

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

### Responses

**200** – Feature toggle deleted

Content-Type: `application/json`

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

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Feature toggle not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/feature_toggles/global?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/global`

List global feature toggles

Returns all global feature toggles with filtering and pagination. Requires superadmin role.

Requires features: feature_toggles.view

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional. Page number for pagination |
| pageSize | query | any | Optional. Number of items per page (max 200) |
| search | query | any | Optional. Case-insensitive search across identifier, name, description, and category |
| type | query | any | Optional. Filter by toggle type (boolean, string, number, json) |
| category | query | any | Optional. Filter by category (case-insensitive partial match) |
| name | query | any | Optional. Filter by name (case-insensitive partial match) |
| identifier | query | any | Optional. Filter by identifier (case-insensitive partial match) |
| sortField | query | any | Optional. Field to sort by |
| sortDir | query | any | Optional. Sort direction (ascending or descending) |

### Responses

**200** – Feature toggles collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "identifier": "string",
      "name": "string",
      "description": null,
      "category": null,
      "type": "boolean",
      "defaultValue": null,
      "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://portal.gt.freighttech.org/api/feature_toggles/global?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/feature_toggles/global`

Create global feature toggle

Creates a new global feature toggle. Requires superadmin role.

Requires features: feature_toggles.global.manage

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.global.manage

### Request Body

Content-Type: `application/json`

```json
{
  "identifier": "string",
  "name": "string",
  "description": null,
  "category": null,
  "type": "boolean",
  "defaultValue": null
}
```

### Responses

**201** – Feature toggle 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://portal.gt.freighttech.org/api/feature_toggles/global" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"identifier\": \"string\",
  \"name\": \"string\",
  \"description\": null,
  \"category\": null,
  \"type\": \"boolean\",
  \"defaultValue\": null
}"
```

## PUT `/feature_toggles/global`

Update global feature toggle

Updates an existing global feature toggle. Requires superadmin role.

Requires features: feature_toggles.global.manage

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.global.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "category": null,
  "defaultValue": null
}
```

### Responses

**200** – Feature toggle updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Feature toggle not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/feature_toggles/global" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"category\": null,
  \"defaultValue\": null
}"
```

## GET `/feature_toggles/global/{id}`

Fetch feature toggle by ID

Returns complete details of a feature toggle.

Requires features: feature_toggles.view

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.view

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

### Responses

**200** – Feature toggle detail

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "identifier": "string",
  "name": "string",
  "description": null,
  "category": null,
  "type": "boolean",
  "defaultValue": null,
  "createdAt": null,
  "updatedAt": null
}
```

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Feature toggle not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/global/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/global/{id}/override`

Fetch feature toggle override

Returns feature toggle override.

Requires features: feature_toggles.view

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.view

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

### Responses

**200** – Feature toggle overrides

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "tenantName": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "toggleType": "boolean",
  "updatedAt": null
}
```

**400** – Invalid request

Content-Type: `application/json`

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

**404** – Feature toggle not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/global/:id/override" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/overrides`

List overrides

Returns list of feature toggle overrides.

Requires features: feature_toggles.view

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| category | query | any | Optional |
| name | query | any | Optional |
| identifier | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – List of overrides

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "toggleId": "00000000-0000-4000-8000-000000000000",
      "tenantName": "string",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "identifier": "string",
      "name": "string",
      "category": "string",
      "isOverride": true
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "isSuperAdmin": true
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/feature_toggles/overrides?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/feature_toggles/overrides`

Change override state

Enable, disable or inherit a feature toggle for a specific tenant.

Requires features: feature_toggles.manage

**Tags:** Feature Toggles

**Requires authentication.**

**Features:** feature_toggles.manage

### Request Body

Content-Type: `application/json`

```json
{
  "toggleId": "00000000-0000-4000-8000-000000000000",
  "isOverride": true
}
```

### Responses

**200** – Override updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "overrideToggleId": null
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**404** – Not found

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/feature_toggles/overrides" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"toggleId\": \"00000000-0000-4000-8000-000000000000\",
  \"isOverride\": true
}"
```

## GET `/gt_accounts/feature-catalog`

GT customer-portal feature catalogue

Requires features: gt_accounts.view

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.view

### Responses

**200** – Catalogue

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/feature-catalog" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/gt_accounts/mobile/login`

Customer sign-in for native (mobile) clients — tokens in the body

**Tags:** GT Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string"
}
```

### Responses

**200** – Signed in

Content-Type: `application/json`

```json
{
  "ok": true,
  "token": "string",
  "refreshToken": "string",
  "expiresIn": 1,
  "user": null,
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Invalid body or tenant

Content-Type: `application/json`

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

**401** – Invalid email or password

Content-Type: `application/json`

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

**404** – Unknown organization slug

Content-Type: `application/json`

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

**429** – Too many attempts

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/mobile/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\"
}"
```

## POST `/gt_accounts/mobile/logout`

Sign out a native (mobile) client: revoke its session

**Tags:** GT Accounts

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Session revoked (or already gone)

Content-Type: `application/json`

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

**400** – Invalid body

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/mobile/logout" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"refreshToken\": \"string\"
}"
```

## POST `/gt_accounts/mobile/refresh`

Refresh the customer access token for native (mobile) clients

**Tags:** GT Accounts

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – New access token

Content-Type: `application/json`

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

**400** – Invalid body

Content-Type: `application/json`

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

**401** – Session revoked, expired or account inactive — sign in again

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/mobile/refresh" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"refreshToken\": \"string\"
}"
```

## POST `/gt_accounts/password-reset`

Request a customer password reset link (always 200; e-mailed when delivery is configured)

**Tags:** GT Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "orgSlug": "string"
}
```

### Responses

**200** – Accepted

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/password-reset" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"orgSlug\": \"string\"
}"
```

## GET `/gt_accounts/portal/assignable-roles`

Customer roles a portal admin can assign

**Tags:** GT Accounts

### Responses

**200** – Roles

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "slug": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/portal/assignable-roles" \
  -H "Accept: application/json"
```

## GET `/gt_accounts/portal/invitations`

Pending invitations of the caller's company (portal.users.invite or .manage)

**Tags:** GT Accounts

### Responses

**200** – Invitations

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "string",
      "email": "string",
      "displayName": null,
      "roles": [
        {
          "id": "string",
          "name": "string"
        }
      ],
      "createdAt": "string",
      "expiresAt": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/portal/invitations" \
  -H "Accept: application/json"
```

## POST `/gt_accounts/portal/invitations`

Invite a colleague: one-time acceptance link (e-mailed when configured, always returned to the inviter)

**Tags:** GT Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invited

Content-Type: `application/json`

```json
{
  "ok": true,
  "invitation": {
    "id": "string",
    "email": "string",
    "displayName": null,
    "roles": [
      {
        "id": "string",
        "name": "string"
      }
    ],
    "createdAt": "string",
    "expiresAt": "string"
  },
  "inviteUrl": "string",
  "emailDelivery": "sent"
}
```

**403** – No invite permission or role not assignable

Content-Type: `application/json`

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

**409** – E-mail already has a portal account

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/portal/invitations" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/gt_accounts/portal/invitations/{id}`

Cancel a pending invitation of the caller's company

**Tags:** GT Accounts

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

### Responses

**200** – Cancelled

Content-Type: `application/json`

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

**404** – No such pending invitation in this company

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/gt_accounts/portal/invitations/:id" \
  -H "Accept: application/json"
```

## GET `/gt_accounts/portal/landing`

Landing page of the signed-in portal user (customer or partner shell)

**Tags:** GT Accounts

### Responses

**200** – Landing

Content-Type: `application/json`

```json
{
  "ok": true,
  "partyKind": "customer",
  "home": "string"
}
```

**401** – Not signed in

Content-Type: `application/json`

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

**403** – No linked portal company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/portal/landing" \
  -H "Accept: application/json"
```

## GET `/gt_accounts/portal/me`

Current portal customer context

**Tags:** GT Accounts

### Responses

**200** – Context

Content-Type: `application/json`

```json
{
  "ok": true,
  "areas": [
    "string"
  ],
  "features": [
    "string"
  ],
  "roles": [
    {
      "slug": "string",
      "name": "string"
    }
  ]
}
```

**403** – No linked portal company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/portal/me" \
  -H "Accept: application/json"
```

## DELETE `/gt_accounts/profiles`

Deactivate (soft-delete) a portal customer profile

Requires features: gt_accounts.manage

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.manage

### Responses

**200** – Deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/gt_accounts/profiles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_accounts/profiles`

List portal customers

Requires features: gt_accounts.view

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.view

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

### Responses

**200** – Profiles

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "companyId": "string",
      "displayName": "string",
      "partyKind": "customer",
      "taxId": null,
      "enabledAreas": [
        "string"
      ]
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/profiles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/gt_accounts/profiles`

Create a portal customer profile for a CRM company

Requires features: gt_accounts.manage

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.manage

### Request Body

Content-Type: `application/json`

```json
{
  "companyId": "00000000-0000-4000-8000-000000000000",
  "displayName": "string",
  "taxId": null,
  "eori": null,
  "serviceCompanies": [],
  "enabledAreas": [
    "dashboard",
    "shipments",
    "customs",
    "documents",
    "invoices",
    "deliveries",
    "offers",
    "reports",
    "news",
    "help"
  ],
  "preferredIdentifier": "gt_ref",
  "paymentTermDays": null,
  "deliveryRules": {},
  "accountManagers": [],
  "peerParties": [],
  "isActive": true,
  "partyKind": "customer"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string",
  "companyId": "string",
  "displayName": "string",
  "partyKind": "customer",
  "taxId": null,
  "enabledAreas": [
    "string"
  ]
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/profiles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"companyId\": \"00000000-0000-4000-8000-000000000000\",
  \"displayName\": \"string\",
  \"taxId\": null,
  \"eori\": null,
  \"serviceCompanies\": [],
  \"enabledAreas\": [
    \"dashboard\",
    \"shipments\",
    \"customs\",
    \"documents\",
    \"invoices\",
    \"deliveries\",
    \"offers\",
    \"reports\",
    \"news\",
    \"help\"
  ],
  \"preferredIdentifier\": \"gt_ref\",
  \"paymentTermDays\": null,
  \"deliveryRules\": {},
  \"accountManagers\": [],
  \"peerParties\": [],
  \"isActive\": true,
  \"partyKind\": \"customer\"
}"
```

## PUT `/gt_accounts/profiles`

Update a portal customer profile

Requires features: gt_accounts.manage

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.manage

### Request Body

Content-Type: `application/json`

```json
{
  "taxId": null,
  "eori": null,
  "paymentTermDays": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "companyId": "string",
  "displayName": "string",
  "partyKind": "customer",
  "taxId": null,
  "enabledAreas": [
    "string"
  ]
}
```

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_accounts/profiles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"taxId\": null,
  \"eori\": null,
  \"paymentTermDays\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/gt_accounts/profiles/{id}`

Portal customer profile detail

Requires features: gt_accounts.view

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.view

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

### Responses

**200** – Profile

Content-Type: `application/json`

```json
{
  "id": "string",
  "userCount": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/profiles/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_accounts/profiles/{id}/invitations`

Pending invitations of a portal company and the roles of its audience

Requires features: gt_accounts.view

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.view

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

### Responses

**200** – Invitations

Content-Type: `application/json`

```json
{
  "ok": true,
  "partyKind": "string",
  "items": [
    {
      "id": "string",
      "email": "string",
      "displayName": null,
      "roles": [
        {
          "id": "string",
          "name": "string"
        }
      ],
      "createdAt": "string",
      "expiresAt": "string"
    }
  ],
  "roles": [
    {
      "id": "string",
      "slug": "string",
      "name": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_accounts/profiles/:id/invitations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/gt_accounts/profiles/{id}/invitations`

Staff invites a user into a portal company (customer or partner) with roles of its audience

Requires features: gt_accounts.manage

**Tags:** GT Accounts

**Requires authentication.**

**Features:** gt_accounts.manage

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

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invited

Content-Type: `application/json`

```json
{
  "ok": true,
  "invitation": {
    "id": "string",
    "email": "string",
    "displayName": null,
    "roles": [
      {
        "id": "string",
        "name": "string"
      }
    ],
    "createdAt": "string",
    "expiresAt": "string"
  },
  "inviteUrl": "string",
  "emailDelivery": "sent"
}
```

**409** – E-mail already has a portal account

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_accounts/profiles/:id/invitations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## GET `/gt_customs/cases`

List projected customs cases (staff, includes unmatched rows and amounts)

Requires features: gt_customs.view

**Tags:** GT Customs

**Requires authentication.**

**Features:** gt_customs.view

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

### Responses

**200** – Customs cases

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "caseReference": null,
      "stepCode": "string",
      "customerCompanyId": null
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_customs/cases?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_customs/portal/by-shipment/{shipmentId}`

Customs cases linked to a shipment (customer)

**Tags:** GT Customs

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

### Responses

**200** – Cases (empty when none or when the shipment is not the company's)

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "caseReference": null,
      "mrn": null,
      "blNumber": null,
      "containerNumbers": [
        "string"
      ],
      "shipmentId": null,
      "shipmentReference": null,
      "stepCode": "string",
      "steps": [
        {
          "code": "string"
        }
      ],
      "inspection": true,
      "missingDocuments": [
        {
          "kind": null,
          "label": "string",
          "blocking": true
        }
      ],
      "cleared": true,
      "releasedAt": null,
      "eta": null,
      "dutyStatus": "paid",
      "vatStatus": "paid",
      "documentCount": 1,
      "updatedAt": "string"
    }
  ]
}
```

**403** – No customs access

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_customs/portal/by-shipment/:shipmentId" \
  -H "Accept: application/json"
```

## GET `/gt_customs/portal/cases`

List customs cases of the signed-in customer company

Company is taken from the customer session. Inspection and hold dates, charge amounts and peer IRIs are never returned.

**Tags:** GT Customs

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

### Responses

**200** – Cases with per-view counts

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "caseReference": null,
      "mrn": null,
      "blNumber": null,
      "containerNumbers": [
        "string"
      ],
      "shipmentId": null,
      "shipmentReference": null,
      "stepCode": "string",
      "steps": [
        {
          "code": "string"
        }
      ],
      "inspection": true,
      "missingDocuments": [
        {
          "kind": null,
          "label": "string",
          "blocking": true
        }
      ],
      "cleared": true,
      "releasedAt": null,
      "eta": null,
      "dutyStatus": "paid",
      "vatStatus": "paid",
      "documentCount": 1,
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "counts": {
    "key": 1
  }
}
```

**401** – No customer session

Content-Type: `application/json`

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

**403** – No customs access for this user or company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_customs/portal/cases?view=all&page=1&pageSize=20" \
  -H "Accept: application/json"
```

## GET `/gt_customs/portal/cases/{id}`

Customs case detail (customer)

**Tags:** GT Customs

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

### Responses

**200** – Case

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "caseReference": null,
    "mrn": null,
    "blNumber": null,
    "containerNumbers": [
      "string"
    ],
    "shipmentId": null,
    "shipmentReference": null,
    "stepCode": "string",
    "steps": [
      {
        "code": "string"
      }
    ],
    "inspection": true,
    "missingDocuments": [
      {
        "kind": null,
        "label": "string",
        "blocking": true
      }
    ],
    "cleared": true,
    "releasedAt": null,
    "eta": null,
    "dutyStatus": "paid",
    "vatStatus": "paid",
    "documentCount": 1,
    "updatedAt": "string"
  }
}
```

**403** – No customs access

Content-Type: `application/json`

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

**404** – Not found for this company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_customs/portal/cases/:id" \
  -H "Accept: application/json"
```

## GET `/gt_deliveries/portal/calendar`

Delivery calendar: day states for selected units and the company request chips (max 120 days)

**Tags:** GT Deliveries

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| from | query | any | Required |
| to | query | any | Required |
| units | query | any | Optional |

### Responses

**200** – Calendar

Content-Type: `application/json`

```json
{
  "ok": true,
  "today": "string",
  "days": [
    {
      "date": "string",
      "state": "free",
      "reason": null
    }
  ],
  "chips": [
    {
      "requestId": "string",
      "date": "string",
      "to": null,
      "window": "string",
      "status": "string",
      "confirmed": true,
      "direction": null,
      "shipmentId": "string",
      "referenceNumber": null,
      "containerNumbers": [
        "string"
      ]
    }
  ],
  "window": {
    "firstPossible": null,
    "freeUntil": null
  }
}
```

**400** – Invalid range

Content-Type: `application/json`

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

**403** – Missing deliveries area or feature

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_deliveries/portal/calendar?from=string&to=string" \
  -H "Accept: application/json"
```

## POST `/gt_deliveries/portal/requests`

Request a delivery slot for units of the current company (one request per shipment)

**Tags:** GT Deliveries

### Request Body

Content-Type: `application/json`

```json
{
  "unitIds": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "mode": "date",
  "date": null,
  "from": null,
  "to": null,
  "window": "string",
  "address": "string",
  "contactName": "string",
  "contactPhone": "string",
  "driverNotes": null
}
```

### Responses

**201** – Requested

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "string",
      "status": "requested",
      "shipmentId": "string",
      "referenceNumber": null,
      "unitIds": [
        "string"
      ],
      "containerNumbers": [
        "string"
      ],
      "mode": "date",
      "requestedDate": null,
      "requestedFrom": null,
      "requestedTo": null,
      "excludedDates": [
        "string"
      ],
      "window": "string",
      "address": null,
      "contactName": null,
      "contactPhone": null,
      "driverNotes": null,
      "decisionNote": null,
      "confirmedDate": null,
      "confirmedWindow": null,
      "driver": null,
      "podAt": null,
      "outsideFreeTime": true,
      "updatedAt": "string",
      "canChange": true,
      "canCancel": true,
      "canReportNotArrived": true
    }
  ]
}
```

**400** – Validation failed or day unavailable (localized `message`)

Content-Type: `application/json`

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

**403** – Missing portal.deliveries.request

Content-Type: `application/json`

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

**404** – Units not found for this company

Content-Type: `application/json`

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

**409** – Unit already requested or delivered

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_deliveries/portal/requests" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"unitIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ],
  \"mode\": \"date\",
  \"date\": null,
  \"from\": null,
  \"to\": null,
  \"window\": \"string\",
  \"address\": \"string\",
  \"contactName\": \"string\",
  \"contactPhone\": \"string\",
  \"driverNotes\": null
}"
```

## PUT `/gt_deliveries/portal/requests/{id}`

Change or cancel an own delivery request while it awaits the desk decision (optimistic lock via `updatedAt`)

**Tags:** GT Deliveries

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

### Request Body

Content-Type: `application/json`

```json
{
  "action": "update",
  "updatedAt": "string"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "string",
    "status": "requested",
    "shipmentId": "string",
    "referenceNumber": null,
    "unitIds": [
      "string"
    ],
    "containerNumbers": [
      "string"
    ],
    "mode": "date",
    "requestedDate": null,
    "requestedFrom": null,
    "requestedTo": null,
    "excludedDates": [
      "string"
    ],
    "window": "string",
    "address": null,
    "contactName": null,
    "contactPhone": null,
    "driverNotes": null,
    "decisionNote": null,
    "confirmedDate": null,
    "confirmedWindow": null,
    "driver": null,
    "podAt": null,
    "outsideFreeTime": true,
    "updatedAt": "string",
    "canChange": true,
    "canCancel": true,
    "canReportNotArrived": true
  }
}
```

**400** – Validation failed or day unavailable

Content-Type: `application/json`

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

**404** – Request not found for this company

Content-Type: `application/json`

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

**409** – Stale version or request already decided

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_deliveries/portal/requests/:id" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"action\": \"update\",
  \"updatedAt\": \"string\"
}"
```

## POST `/gt_deliveries/portal/requests/{id}/not-arrived`

Report that the container did not arrive on the confirmed slot

**Tags:** GT Deliveries

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Reported

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "string",
    "status": "requested",
    "shipmentId": "string",
    "referenceNumber": null,
    "unitIds": [
      "string"
    ],
    "containerNumbers": [
      "string"
    ],
    "mode": "date",
    "requestedDate": null,
    "requestedFrom": null,
    "requestedTo": null,
    "excludedDates": [
      "string"
    ],
    "window": "string",
    "address": null,
    "contactName": null,
    "contactPhone": null,
    "driverNotes": null,
    "decisionNote": null,
    "confirmedDate": null,
    "confirmedWindow": null,
    "driver": null,
    "podAt": null,
    "outsideFreeTime": true,
    "updatedAt": "string",
    "canChange": true,
    "canCancel": true,
    "canReportNotArrived": true
  }
}
```

**404** – Request not found for this company

Content-Type: `application/json`

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

**409** – Stale version or not yet due

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_deliveries/portal/requests/:id/not-arrived" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\",
  \"note\": null
}"
```

## GET `/gt_deliveries/portal/units`

Planner units of the current customer company (with request state, earliest date and free time)

**Tags:** GT Deliveries

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

### Responses

**200** – Units

Content-Type: `application/json`

```json
{
  "ok": true,
  "today": "string",
  "items": [
    {
      "unitId": "string",
      "shipmentId": "string",
      "referenceNumber": "string",
      "clientReference": null,
      "direction": "string",
      "transportMode": null,
      "cargoType": null,
      "label": "string",
      "containerNumber": null,
      "firstPossible": null,
      "freeUntil": null,
      "freeDaysLeft": null,
      "outsideFreeTime": true,
      "plannedWithinFreeTime": true,
      "state": "todo",
      "view": "todo",
      "request": null
    }
  ],
  "counts": {
    "key": 1
  },
  "windows": [
    "string"
  ],
  "canRequest": true,
  "canSeeShipments": true,
  "canSeeDocuments": true
}
```

**401** – No customer session

Content-Type: `application/json`

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

**403** – Missing deliveries area or portal.deliveries.view

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_deliveries/portal/units" \
  -H "Accept: application/json"
```

## GET `/gt_deliveries/requests`

List customer delivery requests (staff)

Requires features: gt_deliveries.view

**Tags:** GT Deliveries

**Requires authentication.**

**Features:** gt_deliveries.view

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

### Responses

**200** – Requests

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "companyName": null,
      "referenceNumber": null,
      "containerNumbers": [
        "string"
      ],
      "mode": "string",
      "requestedDate": null,
      "requestedFrom": null,
      "requestedTo": null,
      "window": "string",
      "status": "string",
      "confirmedDate": null,
      "confirmedWindow": null,
      "driverName": null,
      "truckPlate": null,
      "outsideFreeTime": true,
      "createdAt": null,
      "updatedAt": null
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_deliveries/requests?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/gt_deliveries/requests`

Decide / progress a delivery request: accept (confirmed slot), reject (note), driver & plates, in delivery, delivered (POD). Optimistic lock via header.

Requires features: gt_deliveries.manage

**Tags:** GT Deliveries

**Requires authentication.**

**Features:** gt_deliveries.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**409** – Optimistic lock conflict or invalid transition

Content-Type: `application/json`

```json
{}
```

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_deliveries/requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"action\": \"accept\"
}"
```

## GET `/gt_documents/one-record/submissions/{id}/content`

Download the file of a portal-held ft:DocumentSubmission LO (ONE Record peer with a GET grant)

**Tags:** GT Documents

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**401** – No ONE Record token / session

Content-Type: `application/json`

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

**403** – No access grant

Content-Type: `application/json`

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

**404** – Unknown LO or no stored file

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/one-record/submissions/:id/content" \
  -H "Accept: application/json"
```

## GET `/gt_documents/portal/documents`

List the customer company documents (by shipment / customs case), own uploads and missing documents

**Tags:** GT Documents

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| shipmentId | query | any | Optional |
| customsCaseId | query | any | Optional |

### Responses

**200** – Documents

Content-Type: `application/json`

```json
{
  "ok": true,
  "documents": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": null,
      "identifier": null,
      "type": null,
      "category": "transport",
      "commercial": true,
      "documentDate": null,
      "sources": [
        "shipment"
      ],
      "shipmentId": null,
      "shipmentReference": null,
      "customsCaseId": null,
      "customsCaseReference": null,
      "invoiceId": null,
      "contentUrl": "string"
    }
  ],
  "uploads": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "documentType": "string",
      "fileName": "string",
      "mimeType": null,
      "fileSize": null,
      "note": null,
      "status": "pending_review",
      "reviewNote": null,
      "shipmentId": null,
      "shipmentReference": null,
      "customsCaseId": null,
      "customsCaseReference": null,
      "createdAt": "string",
      "reviewedAt": null,
      "updatedAt": "string",
      "contentUrl": "string"
    }
  ],
  "missing": [
    {
      "kind": null,
      "label": "string",
      "uploadType": "string",
      "blocking": true,
      "caseId": "string",
      "caseReference": null
    }
  ],
  "missingCount": 1,
  "complete": true,
  "shipmentReference": null,
  "canUpload": true,
  "canViewFinance": true
}
```

**401** – Not signed in

Content-Type: `application/json`

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

**403** – Missing documents area or portal.documents.view

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/portal/documents" \
  -H "Accept: application/json"
```

## GET `/gt_documents/portal/documents/{id}/content`

Open a document (proxied from the owning peer after the company link check)

Query `?download=1` forces a download. Accessible with portal.documents.view, or with portal.invoices.view for invoice PDFs.

**Tags:** GT Documents

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**403** – No documents / invoices access

Content-Type: `application/json`

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

**404** – Not linked to this company, blocked, hidden or unknown

Content-Type: `application/json`

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

**502** – Peer content unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/portal/documents/:id/content" \
  -H "Accept: application/json"
```

## GET `/gt_documents/portal/uploads`

List the customer company uploads

**Tags:** GT Documents

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| shipmentId | query | any | Optional |
| customsCaseId | query | any | Optional |

### Responses

**200** – Uploads

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "documentType": "string",
      "fileName": "string",
      "mimeType": null,
      "fileSize": null,
      "note": null,
      "status": "pending_review",
      "reviewNote": null,
      "shipmentId": null,
      "shipmentReference": null,
      "customsCaseId": null,
      "customsCaseReference": null,
      "createdAt": "string",
      "reviewedAt": null,
      "updatedAt": "string",
      "contentUrl": "string"
    }
  ],
  "canUpload": true
}
```

**403** – Missing documents area or feature

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/portal/uploads" \
  -H "Accept: application/json"
```

## POST `/gt_documents/portal/uploads`

Upload a document for GT verification (multipart: file, documentType, shipmentId and/or customsCaseId, note)

Max 20 MB; pdf, jpg, png, xlsx, docx, msg (content is sniffed). The upload starts as pending_review.

**Tags:** GT Documents

### Request Body

Content-Type: `multipart/form-data`

```text
documentType=commercial_invoice
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "documentType": "string",
    "fileName": "string",
    "mimeType": null,
    "fileSize": null,
    "note": null,
    "status": "pending_review",
    "reviewNote": null,
    "shipmentId": null,
    "shipmentReference": null,
    "customsCaseId": null,
    "customsCaseReference": null,
    "createdAt": "string",
    "reviewedAt": null,
    "updatedAt": "string",
    "contentUrl": "string"
  }
}
```

**400** – Validation failed (fieldErrors.file: file_empty | file_type)

Content-Type: `application/json`

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

**403** – Missing portal.documents.upload

Content-Type: `application/json`

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

**404** – Shipment / customs case not found for this company

Content-Type: `application/json`

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

**413** – File larger than 20 MB

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_documents/portal/uploads" \
  -H "Accept: application/json" \
  -H "Content-Type: multipart/form-data" \
  -d "{
  \"documentType\": \"commercial_invoice\"
}"
```

## GET `/gt_documents/portal/uploads/{id}/content`

Open one of the customer company uploads

**Tags:** GT Documents

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**404** – Not an upload of this company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/portal/uploads/:id/content" \
  -H "Accept: application/json"
```

## GET `/gt_documents/uploads`

List customer document uploads (staff review queue)

Requires features: gt_documents.uploads.view

**Tags:** GT Documents

**Requires authentication.**

**Features:** gt_documents.uploads.view

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

### Responses

**200** – Uploads

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "companyName": null,
      "shipmentReference": null,
      "customsCaseReference": null,
      "documentType": "string",
      "fileName": "string",
      "mimeType": null,
      "fileSize": null,
      "note": null,
      "status": "pending_review",
      "reviewedAt": null,
      "reviewNote": null,
      "previewUrl": "string",
      "createdAt": null,
      "updatedAt": null
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/uploads?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/gt_documents/uploads`

Verify or reject a customer upload (reject requires a note; optimistic lock via updatedAt header)

Requires features: gt_documents.uploads.review

**Tags:** GT Documents

**Requires authentication.**

**Features:** gt_documents.uploads.review

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "status": "verified",
  "reviewNote": null
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "companyName": null,
  "shipmentReference": null,
  "customsCaseReference": null,
  "documentType": "string",
  "fileName": "string",
  "mimeType": null,
  "fileSize": null,
  "note": null,
  "status": "pending_review",
  "reviewedAt": null,
  "reviewNote": null,
  "previewUrl": "string",
  "createdAt": null,
  "updatedAt": null
}
```

**409** – Optimistic lock conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_documents/uploads" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"status\": \"verified\",
  \"reviewNote\": null
}"
```

## GET `/gt_documents/uploads/{id}/content`

Preview / download a customer upload (staff)

Requires features: gt_documents.uploads.view

**Tags:** GT Documents

**Requires authentication.**

**Features:** gt_documents.uploads.view

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**404** – Not found in the selected organization

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_documents/uploads/:id/content" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_invoices/inquiries`

List customer invoice inquiries (staff)

Requires features: gt_invoices.view

**Tags:** GT Invoices

**Requires authentication.**

**Features:** gt_invoices.view

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

### Responses

**200** – Inquiries

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "invoiceId": "string",
      "invoiceNumber": null,
      "companyName": null,
      "kind": "contact",
      "message": null,
      "paidOn": null,
      "attachmentUrl": null,
      "status": "submitted",
      "staffNote": null,
      "handledAt": null,
      "createdAt": null,
      "updatedAt": null
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_invoices/inquiries?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/gt_invoices/inquiries`

Acknowledge / resolve an inquiry and add a staff note (optimistic lock via updatedAt header)

Requires features: gt_invoices.inquiries.manage

**Tags:** GT Invoices

**Requires authentication.**

**Features:** gt_invoices.inquiries.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "invoiceId": "string",
  "invoiceNumber": null,
  "companyName": null,
  "kind": "contact",
  "message": null,
  "paidOn": null,
  "attachmentUrl": null,
  "status": "submitted",
  "staffNote": null,
  "handledAt": null,
  "createdAt": null,
  "updatedAt": null
}
```

**409** – Optimistic lock conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_invoices/inquiries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"staffNote\": null
}"
```

## GET `/gt_invoices/one-record/inquiries/{id}/attachment`

Download the attachment of a portal-held ft:InvoiceInquiry LO (ONE Record peer with a GET grant)

**Tags:** GT Invoices

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**401** – No ONE Record token / session

Content-Type: `application/json`

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

**403** – No access grant

Content-Type: `application/json`

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

**404** – Unknown LO or no attachment

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_invoices/one-record/inquiries/:id/attachment" \
  -H "Accept: application/json"
```

## GET `/gt_invoices/portal/export`

Export the current customer company invoices as CSV

**Tags:** GT Invoices

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| view | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – CSV file (UTF-8 with BOM, `;` separated)

Content-Type: `application/json`

```json
"string"
```

**403** – Missing invoices area or feature

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_invoices/portal/export?view=all" \
  -H "Accept: application/json"
```

## GET `/gt_invoices/portal/inquiries`

List the current customer company invoice inquiries

**Tags:** GT Invoices

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

### Responses

**200** – Inquiries

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "invoiceId": "00000000-0000-4000-8000-000000000000",
      "invoiceNumber": null,
      "kind": "contact",
      "message": null,
      "paidOn": null,
      "hasAttachment": true,
      "status": "submitted",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ]
}
```

**403** – Missing invoices area or feature

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_invoices/portal/inquiries?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/gt_invoices/portal/inquiries`

Submit an invoice contact request or payment notice (JSON or multipart with `file`)

**Tags:** GT Invoices

### Request Body

Content-Type: `application/json`

```json
{
  "invoiceId": "00000000-0000-4000-8000-000000000000",
  "kind": "contact"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "invoiceId": "00000000-0000-4000-8000-000000000000",
    "invoiceNumber": null,
    "kind": "contact",
    "message": null,
    "paidOn": null,
    "hasAttachment": true,
    "status": "submitted",
    "createdAt": "string",
    "updatedAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**403** – Missing portal.invoices.inquire

Content-Type: `application/json`

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

**404** – Invoice not found for this company

Content-Type: `application/json`

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

**409** – Invoice already paid (payment notice)

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_invoices/portal/inquiries" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"invoiceId\": \"00000000-0000-4000-8000-000000000000\",
  \"kind\": \"contact\"
}"
```

## GET `/gt_invoices/portal/invoices`

List the current customer company invoices (Finanse)

**Tags:** GT Invoices

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

### Responses

**200** – Invoices, view counts and the header summary

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "invoiceNumber": "string",
      "issueDate": null,
      "dueDate": null,
      "grossAmount": null,
      "currency": null,
      "status": "paid",
      "daysToDue": null,
      "ksefNumber": null,
      "folders": [
        {
          "reference": null,
          "shipmentId": null
        }
      ],
      "inquiries": {
        "key": {
          "id": "string",
          "status": "string",
          "createdAt": "string",
          "paidOn": null
        }
      }
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "counts": {
    "all": 1,
    "due": 1,
    "overdue": 1,
    "paid": 1
  },
  "summary": {
    "dueTotal": {
      "key": 1
    },
    "overdueTotal": {
      "key": 1
    },
    "overdueCount": 1,
    "onTimePct": null,
    "paymentTermDays": null
  },
  "canInquire": true
}
```

**401** – Not signed in

Content-Type: `application/json`

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

**403** – Missing invoices area or feature

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_invoices/portal/invoices?view=all&page=1&pageSize=20" \
  -H "Accept: application/json"
```

## GET `/gt_invoices/portal/invoices/{id}/pdf`

Open the invoice PDF (redirects to the scoped document content proxy)

**Tags:** GT Invoices

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

### Responses

**200** – Success response

Content-Type: `application/json`

**302** – Redirect to the document content

Content-Type: `application/json`

**404** – No PDF for this invoice or not the customer's invoice

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_invoices/portal/invoices/:id/pdf" \
  -H "Accept: application/json"
```

## GET `/gt_offers/order-requests`

List order-from-offer requests (staff queue)

Requires features: gt_offers.view

**Tags:** GT Offers

**Requires authentication.**

**Features:** gt_offers.view

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

### Responses

**200** – Order requests

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "companyName": null,
      "routeLabel": null,
      "status": "submitted",
      "createdFolderReference": null,
      "updatedAt": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_offers/order-requests?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/gt_offers/order-requests`

Accept (with the created FMS folder reference) or reject (with a note) an order request

Requires features: gt_offers.manage

**Tags:** GT Offers

**Requires authentication.**

**Features:** gt_offers.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Decided

Content-Type: `application/json`

```json
{
  "id": "string",
  "companyName": null,
  "routeLabel": null,
  "status": "submitted",
  "createdFolderReference": null,
  "updatedAt": "string"
}
```

**409** – Already decided or modified concurrently (optimistic lock)

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_offers/order-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"decision\": \"accept\"
}"
```

## GET `/gt_offers/portal/offers`

List the customer company offers (portal)

**Tags:** GT Offers

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

### Responses

**200** – Offers

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "origin": null,
      "destination": null,
      "carriers": [
        "string"
      ],
      "containerTypes": [
        "string"
      ],
      "transportMode": null,
      "validUntil": null,
      "daysLeft": null,
      "expired": true,
      "fromPrice": [
        {
          "amount": 1,
          "currency": "string"
        }
      ],
      "orders": {
        "pending": 1,
        "accepted": 1,
        "rejected": 1
      }
    }
  ],
  "total": 1,
  "counts": {
    "active": 1,
    "all": 1
  },
  "canOrder": true
}
```

**401** – Not signed in

Content-Type: `application/json`

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

**403** – No access to offers

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_offers/portal/offers?view=active&page=1&pageSize=50" \
  -H "Accept: application/json"
```

## GET `/gt_offers/portal/offers/{id}`

Customer offer detail with carrier variants and order requests (portal)

**Tags:** GT Offers

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

### Responses

**200** – Offer

Content-Type: `application/json`

```json
{
  "ok": true,
  "offer": {
    "id": "string"
  },
  "orderRequests": [
    {
      "id": "string",
      "status": "string"
    }
  ],
  "canOrder": true
}
```

**404** – Unknown or another company offer

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_offers/portal/offers/:id" \
  -H "Accept: application/json"
```

## GET `/gt_offers/portal/order-requests`

List the company order-from-offer requests (portal)

**Tags:** GT Offers

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

### Responses

**200** – Order requests

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "offerId": "00000000-0000-4000-8000-000000000000",
      "status": "submitted",
      "gtReference": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_offers/portal/order-requests" \
  -H "Accept: application/json"
```

## POST `/gt_offers/portal/order-requests`

Submit an order from an offer (portal)

**Tags:** GT Offers

### Request Body

Content-Type: `application/json`

```json
{
  "offerId": "00000000-0000-4000-8000-000000000000",
  "containers": [],
  "commodity": "string",
  "insurance": false
}
```

### Responses

**201** – Submitted, awaiting GT acceptance

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "offerId": "00000000-0000-4000-8000-000000000000",
    "status": "submitted",
    "gtReference": null
  }
}
```

**400** – Invalid request or lane

Content-Type: `application/json`

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

**403** – Ordering not allowed for this user

Content-Type: `application/json`

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

**404** – Unknown or another company offer

Content-Type: `application/json`

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

**409** – Offer expired

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_offers/portal/order-requests" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"offerId\": \"00000000-0000-4000-8000-000000000000\",
  \"containers\": [],
  \"commodity\": \"string\",
  \"insurance\": false
}"
```

## GET `/gt_partners/agent/dashboard`

Agent dashboard counts (open RFQs, bookings to confirm, departures due, shipments) (agent.dashboard.view)

**Tags:** GT Partners

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/agent/dashboard" \
  -H "Accept: application/json"
```

## GET `/gt_partners/agent/rfqs`

RFQs addressed to the callers agent company (view = open | all) (agent.rfq.view)

**Tags:** GT Partners

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/agent/rfqs" \
  -H "Accept: application/json"
```

## GET `/gt_partners/agent/rfqs/{id}`

RFQ detail with the companys own quotes (agent.rfq.view)

**Tags:** GT Partners

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

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/agent/rfqs/:id" \
  -H "Accept: application/json"
```

## POST `/gt_partners/agent/rfqs/{id}/quotes`

Quote an RFQ → ft:AgentQuote (409 when withdrawn / closed / past due) (agent.rfq.quote)

**Tags:** GT Partners

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

### Request Body

Content-Type: `application/json`

```json
{
  "currency": "string",
  "validUntil": "string",
  "lines": [
    {
      "chargeCode": "string",
      "amount": 1,
      "unit": "PER_CONTAINER",
      "quantity": 1
    }
  ]
}
```

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

**409** – Not possible in the current state (returns it)

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/agent/rfqs/:id/quotes" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"currency\": \"string\",
  \"validUntil\": \"string\",
  \"lines\": [
    {
      \"chargeCode\": \"string\",
      \"amount\": 1,
      \"unit\": \"PER_CONTAINER\",
      \"quantity\": 1
    }
  ]
}"
```

## GET `/gt_partners/agent/shipments`

Origin shipments of the callers agent company (view = to_book | to_dispatch | dispatched | all) (agent.shipments.view)

**Tags:** GT Partners

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/agent/shipments" \
  -H "Accept: application/json"
```

## GET `/gt_partners/agent/shipments/{id}`

Origin shipment detail with confirmations and documents sent (agent.shipments.view)

**Tags:** GT Partners

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

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/agent/shipments/:id" \
  -H "Accept: application/json"
```

## POST `/gt_partners/agent/shipments/{id}/booking-confirmations`

Confirm the carrier booking → ft:BookingConfirmation (agent.bookings.confirm)

**Tags:** GT Partners

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

### Request Body

Content-Type: `application/json`

```json
{
  "bookingNumber": "string"
}
```

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

**409** – Not possible in the current state (returns it)

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/agent/shipments/:id/booking-confirmations" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"bookingNumber\": \"string\"
}"
```

## POST `/gt_partners/agent/shipments/{id}/dispatch-confirmations`

Confirm dispatch (cargo departed) → ft:DispatchConfirmation (agent.dispatch.confirm)

**Tags:** GT Partners

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

### Request Body

Content-Type: `application/json`

```json
{
  "atd": "string",
  "transportDocumentType": "BL",
  "transportDocumentNumber": "string",
  "containers": []
}
```

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/agent/shipments/:id/dispatch-confirmations" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"atd\": \"string\",
  \"transportDocumentType\": \"BL\",
  \"transportDocumentNumber\": \"string\",
  \"containers\": []
}"
```

## POST `/gt_partners/agent/shipments/{id}/documents`

Upload an origin document (multipart file + documentType) → ft:DocumentSubmission (agent.documents.upload)

**Tags:** GT Partners

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

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not an agent session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/agent/shipments/:id/documents" \
  -H "Accept: application/json"
```

## GET `/gt_partners/agent/users`

Agent company users, pending invitations and assignable roles (agent.users.manage)

**Tags:** GT Partners

### Responses

**200** – Users

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "string",
      "email": "string",
      "displayName": "string",
      "isActive": true,
      "lastLoginAt": null,
      "roles": [
        {
          "slug": "string",
          "name": "string"
        }
      ]
    }
  ]
}
```

**403** – Not a agent session or no permission

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/agent/users" \
  -H "Accept: application/json"
```

## POST `/gt_partners/agent/users/invitations`

Invite a colleague into the agent company (agent.users.manage)

**Tags:** GT Partners

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invited

Content-Type: `application/json`

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

**403** – Role of another audience / not a agent admin

Content-Type: `application/json`

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

**409** – E-mail already has a portal account

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/agent/users/invitations" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/gt_partners/agent/users/invitations/{id}`

Cancel a pending invitation of the agent company

**Tags:** GT Partners

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

### Responses

**200** – Cancelled

Content-Type: `application/json`

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

**404** – No such pending invitation

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/gt_partners/agent/users/invitations/:id" \
  -H "Accept: application/json"
```

## GET `/gt_partners/haulier/dashboard`

Haulier dashboard counts (today, upcoming, in transit, POD missing) (haulier.dashboard.view)

**Tags:** GT Partners

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not a haulier session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/haulier/dashboard" \
  -H "Accept: application/json"
```

## GET `/gt_partners/haulier/jobs`

Haulage jobs of the callers company (view = today | upcoming | active | done | all) (haulier.jobs.view)

**Tags:** GT Partners

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not a haulier session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/haulier/jobs" \
  -H "Accept: application/json"
```

## GET `/gt_partners/haulier/jobs/{id}`

Haulage job detail with its events (haulier.jobs.view)

**Tags:** GT Partners

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

### Responses

**200** – OK

Content-Type: `application/json`

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

**403** – Not a haulier session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/haulier/jobs/:id" \
  -H "Accept: application/json"
```

## POST `/gt_partners/haulier/jobs/{id}/deliver`

Confirm delivery → ft:HaulageEvent DELIVERED (409 when not picked up) (haulier.jobs.deliver)

**Tags:** GT Partners

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

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not a haulier session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/haulier/jobs/:id/deliver" \
  -H "Accept: application/json"
```

## POST `/gt_partners/haulier/jobs/{id}/pickup`

Confirm pick-up → ft:HaulageEvent PICKED_UP (409 when not assigned) (haulier.jobs.pickup)

**Tags:** GT Partners

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

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not a haulier session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/haulier/jobs/:id/pickup" \
  -H "Accept: application/json"
```

## POST `/gt_partners/haulier/jobs/{id}/pod`

Upload the POD (photo / PDF, multipart file) → ft:HaulageEvent POD_UPLOADED (haulier.pod.upload)

**Tags:** GT Partners

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

### Responses

**201** – OK

Content-Type: `application/json`

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

**403** – Not a haulier session or missing feature

Content-Type: `application/json`

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

**404** – Not found in the caller company

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/haulier/jobs/:id/pod" \
  -H "Accept: application/json"
```

## GET `/gt_partners/haulier/users`

Haulier company users, pending invitations and assignable roles (haulier.users.manage)

**Tags:** GT Partners

### Responses

**200** – Users

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "string",
      "email": "string",
      "displayName": "string",
      "isActive": true,
      "lastLoginAt": null,
      "roles": [
        {
          "slug": "string",
          "name": "string"
        }
      ]
    }
  ]
}
```

**403** – Not a haulier session or no permission

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/haulier/users" \
  -H "Accept: application/json"
```

## POST `/gt_partners/haulier/users/invitations`

Invite a colleague into the haulier company (haulier.users.manage)

**Tags:** GT Partners

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invited

Content-Type: `application/json`

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

**403** – Role of another audience / not a haulier admin

Content-Type: `application/json`

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

**409** – E-mail already has a portal account

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_partners/haulier/users/invitations" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/gt_partners/haulier/users/invitations/{id}`

Cancel a pending invitation of the haulier company

**Tags:** GT Partners

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

### Responses

**200** – Cancelled

Content-Type: `application/json`

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

**404** – No such pending invitation

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/gt_partners/haulier/users/invitations/:id" \
  -H "Accept: application/json"
```

## GET `/gt_partners/one-record/documents/{id}/content`

Download the file of a portal-held partner LO (ONE Record peer with a GET grant)

**Tags:** GT Partners

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**401** – No ONE Record token / session

Content-Type: `application/json`

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

**403** – No access grant

Content-Type: `application/json`

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

**404** – Unknown LO or no stored file

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/one-record/documents/:id/content" \
  -H "Accept: application/json"
```

## GET `/gt_partners/one-record/haulage-events/{id}/content`

Download the file of a portal-held partner LO (ONE Record peer with a GET grant)

**Tags:** GT Partners

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

### Responses

**200** – File bytes

Content-Type: `application/json`

**401** – No ONE Record token / session

Content-Type: `application/json`

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

**403** – No access grant

Content-Type: `application/json`

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

**404** – Unknown LO or no stored file

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_partners/one-record/haulage-events/:id/content" \
  -H "Accept: application/json"
```

## DELETE `/gt_peers/connections`

Soft-delete a peer connection

Requires features: gt_peers.manage

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.manage

### Responses

**200** – Deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/gt_peers/connections" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_peers/connections`

List federated peer connections

Requires features: gt_peers.view

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.view

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

### Responses

**200** – Peer connections

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "code": "string",
      "name": "string",
      "role": "string",
      "baseIri": "string",
      "tokenUrl": "string",
      "clientId": "string",
      "hasClientSecret": true,
      "hasInboundSecret": true,
      "inboundPath": "string",
      "enabledTypes": [
        "string"
      ],
      "status": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/connections?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/gt_peers/connections`

Create a peer connection

Requires features: gt_peers.manage

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.manage

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "name": "string",
  "role": "tms",
  "baseIri": "https://example.com/resource",
  "tokenUrl": "https://example.com/resource",
  "clientId": "string",
  "clientSecret": "string",
  "audience": null,
  "inboundSecret": null,
  "enabledTypes": [],
  "knownIris": [],
  "serviceCompany": null,
  "status": "active"
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "code": "string",
  "name": "string",
  "role": "string",
  "baseIri": "string",
  "tokenUrl": "string",
  "clientId": "string",
  "hasClientSecret": true,
  "hasInboundSecret": true,
  "inboundPath": "string",
  "enabledTypes": [
    "string"
  ],
  "status": "string"
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_peers/connections" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"name\": \"string\",
  \"role\": \"tms\",
  \"baseIri\": \"https://example.com/resource\",
  \"tokenUrl\": \"https://example.com/resource\",
  \"clientId\": \"string\",
  \"clientSecret\": \"string\",
  \"audience\": null,
  \"inboundSecret\": null,
  \"enabledTypes\": [],
  \"knownIris\": [],
  \"serviceCompany\": null,
  \"status\": \"active\"
}"
```

## PUT `/gt_peers/connections`

Update a peer connection (empty secrets keep the stored value; changing the baseIri/tokenUrl origin requires a new clientSecret)

Requires features: gt_peers.manage

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.manage

### Request Body

Content-Type: `application/json`

```json
{
  "audience": null,
  "inboundSecret": null,
  "serviceCompany": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "code": "string",
  "name": "string",
  "role": "string",
  "baseIri": "string",
  "tokenUrl": "string",
  "clientId": "string",
  "hasClientSecret": true,
  "hasInboundSecret": true,
  "inboundPath": "string",
  "enabledTypes": [
    "string"
  ],
  "status": "string"
}
```

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_peers/connections" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"audience\": null,
  \"inboundSecret\": null,
  \"serviceCompany\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/gt_peers/connections/{id}/sync`

Queue discovery + refresh of a peer connection

Requires features: gt_peers.manage

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.manage

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**202** – Reconciliation queued

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_peers/connections/:id/sync" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/gt_peers/inbound/{connectionId}`

Receive a signed ONE Record notification from a federated peer

**Tags:** GT Peers

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

### Responses

**204** – Accepted; the object is queued for fetch

**400** – Malformed notification body

Content-Type: `application/json`

```json
{}
```

**401** – Unknown connection, invalid or stale signature

Content-Type: `application/json`

```json
{}
```

**422** – Notified IRI does not belong to this peer

Content-Type: `application/json`

```json
{}
```

**503** – Notification could not be queued; retry later

Content-Type: `application/json`

```json
{}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_peers/inbound/:connectionId" \
  -H "Accept: application/json"
```

## GET `/gt_peers/objects`

List locally cached Logistics Objects

Requires features: gt_peers.view

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.view

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

### Responses

**200** – Remote objects

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "iri": "string",
      "loType": "string",
      "status": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/objects?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/gt_peers/objects/fetch`

Fetch one Logistics Object from a peer immediately

Requires features: gt_peers.manage

**Tags:** GT Peers

**Requires authentication.**

**Features:** gt_peers.manage

### Request Body

Content-Type: `application/json`

```json
{
  "connectionId": "00000000-0000-4000-8000-000000000000",
  "iri": "https://example.com/resource"
}
```

### Responses

**200** – Fetch result

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_peers/objects/fetch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"connectionId\": \"00000000-0000-4000-8000-000000000000\",
  \"iri\": \"https://example.com/resource\"
}"
```

## GET `/gt_peers/one-record/logistics-objects`

List Logistics Objects (type, changedSince, cursor, limit ≤ 100); scoped by the peer's grants or the staff feature

**Tags:** ONE Record

### Responses

**200** – OK

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Staff session without the type feature

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects" \
  -H "Accept: application/json"
```

## GET `/gt_peers/one-record/logistics-objects/{id}`

Logistics Object (JSON-LD); ONE Record peer token or staff session, checked in-handler

**Tags:** ONE Record

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

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects/:id" \
  -H "Accept: application/json"
```

## PATCH `/gt_peers/one-record/logistics-objects/{id}`

ChangeRequest on a Logistics Object (inbound writes are disabled on the portal → 403)

**Tags:** ONE Record

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

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects/:id" \
  -H "Accept: application/json"
```

## GET `/gt_peers/one-record/logistics-objects/{id}/audit-trail`

Audit trail of an LO (staff only, unchanged)

Requires features: one_record.objects.view

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.objects.view

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

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects/:id/audit-trail" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_peers/one-record/logistics-objects/{id}/content`

Binary content of a document LO (in-handler ONE Record authz)

**Tags:** ONE Record

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

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects/:id/content" \
  -H "Accept: application/json"
```

## GET `/gt_peers/one-record/logistics-objects/{id}/logistics-events`

Logistics events of an LO (in-handler ONE Record authz)

**Tags:** ONE Record

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

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects/:id/logistics-events" \
  -H "Accept: application/json"
```

## GET `/gt_peers/one-record/logistics-objects/{id}/logistics-events/{eventId}`

One logistics event of an LO (in-handler ONE Record authz)

**Tags:** ONE Record

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

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/logistics-objects/:id/logistics-events/:eventId" \
  -H "Accept: application/json"
```

## GET `/gt_peers/one-record/oauth/jwks`

JWKS of the ONE Record M2M issuer

**Tags:** ONE Record

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/oauth/jwks" \
  -H "Accept: application/json"
```

## GET `/gt_peers/one-record/oauth/metadata`

Discovery document of the ONE Record M2M issuer

**Tags:** ONE Record

### Responses

**200** – OK

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_peers/one-record/oauth/metadata" \
  -H "Accept: application/json"
```

## POST `/gt_peers/one-record/oauth/token`

OAuth2 client_credentials token (ONE Record M2M issuer); rate limited per IP and per client_id + IP

**Tags:** ONE Record

### Responses

**200** – OK

Content-Type: `application/json`

**429** – Too many token requests

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_peers/one-record/oauth/token" \
  -H "Accept: application/json"
```

## DELETE `/gt_portal/news`

Delete a news post

Requires features: gt_portal.news.manage

**Tags:** GT Portal

**Requires authentication.**

**Features:** gt_portal.news.manage

### Responses

**200** – Deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/gt_portal/news" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_portal/news`

List news posts (staff)

Requires features: gt_portal.news.view

**Tags:** GT Portal

**Requires authentication.**

**Features:** gt_portal.news.view

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

### Responses

**200** – Posts

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "category": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_portal/news?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/gt_portal/news`

Create a news post

Requires features: gt_portal.news.manage

**Tags:** GT Portal

**Requires authentication.**

**Features:** gt_portal.news.manage

### Request Body

Content-Type: `application/json`

```json
{
  "title": "string",
  "body": "",
  "category": "gt",
  "publishedAt": null,
  "pinned": false,
  "serviceCompany": null,
  "audienceCompanyIds": []
}
```

### Responses

**201** – Created

Content-Type: `application/json`

```json
{
  "id": "string",
  "title": "string",
  "category": "string"
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_portal/news" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"title\": \"string\",
  \"body\": \"\",
  \"category\": \"gt\",
  \"publishedAt\": null,
  \"pinned\": false,
  \"serviceCompany\": null,
  \"audienceCompanyIds\": []
}"
```

## PUT `/gt_portal/news`

Update a news post

Requires features: gt_portal.news.manage

**Tags:** GT Portal

**Requires authentication.**

**Features:** gt_portal.news.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "title": "string",
  "category": "string"
}
```

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/gt_portal/news" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"publishedAt\": null,
  \"serviceCompany\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/gt_portal/portal/dashboard`

Pulpit aggregate for the current customer (sections gated by role and company areas)

**Tags:** GT Portal

### Responses

**200** – Dashboard

Content-Type: `application/json`

```json
{
  "company": {
    "displayName": "string"
  }
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_portal/portal/dashboard" \
  -H "Accept: application/json"
```

## GET `/gt_portal/portal/news`

Portal news feed for the current customer

**Tags:** GT Portal

### Responses

**200** – Posts

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_portal/portal/news" \
  -H "Accept: application/json"
```

## GET `/gt_portal/portal/search`

Global portal search: shipments, customs cases, invoices and documents of the session company

Groups are gated by role feature × company area (invoices: portal.invoices.view; documents: portal.documents.view, finance documents also need portal.invoices.view). Max 5 hits per group.

**Tags:** GT Portal

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

### Responses

**200** – Grouped results

Content-Type: `application/json`

```json
{
  "ok": true,
  "query": "string",
  "groups": [
    {
      "id": "shipments",
      "items": [
        {
          "id": "string",
          "kind": "shipments",
          "title": "string",
          "subtitle": null,
          "code": null,
          "amount": null,
          "currency": null
        }
      ]
    }
  ]
}
```

**400** – Query shorter than 2 or longer than 100 characters

Content-Type: `application/json`

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

**401** – Not signed in

Content-Type: `application/json`

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

**403** – No portal profile or no dashboard access

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_portal/portal/search?q=string" \
  -H "Accept: application/json"
```

## GET `/gt_reports/portal/export`

Download the report of the customer session company as an Excel workbook (.xlsx, one sheet per tab)

**Tags:** GT Reports

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| from | query | any | Optional |
| to | query | any | Optional |
| groupBy | query | any | Optional |

### Responses

**200** – application/vnd.openxmlformats-officedocument.spreadsheetml.sheet workbook (.xlsx)

Content-Type: `application/json`

```json
"string"
```

**400** – Invalid period

Content-Type: `application/json`

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

**401** – No customer session

Content-Type: `application/json`

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

**403** – Missing reports area or portal.reports.view

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_reports/portal/export?groupBy=month" \
  -H "Accept: application/json"
```

## GET `/gt_reports/portal/summary`

Report summary (turnover, shipments, TEU, AIR, on-time %, CO₂) for the customer session company

**Tags:** GT Reports

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| from | query | any | Optional |
| to | query | any | Optional |
| groupBy | query | any | Optional |

### Responses

**200** – Report computed on demand

Content-Type: `application/json`

```json
{
  "ok": true,
  "period": {
    "from": "string",
    "to": "string",
    "groupBy": "month",
    "wholeCooperation": true
  },
  "buckets": [
    "string"
  ],
  "kpis": {
    "turnoverNet": {
      "key": 1
    },
    "turnoverGross": {
      "key": 1
    },
    "primaryCurrency": null,
    "invoices": 1,
    "shipments": 1,
    "containers": 1,
    "teu": 1,
    "airKg": 1,
    "airShipments": 1,
    "lclShipments": 1,
    "lclCbm": null,
    "onTimePct": null,
    "paidInvoices": 1,
    "co2Kg": 1
  },
  "series": {
    "turnover": [
      {
        "key": "string",
        "net": {
          "key": 1
        },
        "gross": {
          "key": 1
        },
        "invoices": 1
      }
    ],
    "shipments": [
      {
        "key": "string",
        "total": 1,
        "byMode": {
          "OCEAN": 1,
          "AIR": 1,
          "ROAD": 1,
          "RAIL": 1,
          "OTHER": 1
        },
        "imports": 1,
        "exports": 1,
        "lcl": 1,
        "lclCbm": null
      }
    ],
    "teu": [
      {
        "key": "string",
        "containers": 1,
        "teu": 1,
        "c20": 1,
        "c40": 1,
        "unknownType": 1
      }
    ],
    "air": [
      {
        "key": "string",
        "shipments": 1,
        "kg": 1,
        "withoutWeight": 1
      }
    ],
    "onTimePct": [
      {
        "key": "string",
        "paid": 1,
        "onTime": 1,
        "pct": null,
        "overdueOpen": 1
      }
    ],
    "co2": [
      {
        "key": "string",
        "kg": 1,
        "byMode": {
          "OCEAN": 1,
          "AIR": 1,
          "ROAD": 1,
          "RAIL": 1,
          "OTHER": 1
        },
        "estimated": 1,
        "notEstimated": 1
      }
    ]
  },
  "breakdown": {
    "byMode": [
      {
        "mode": "string",
        "count": 1
      }
    ],
    "turnoverByMode": [
      {
        "mode": "string",
        "net": {
          "key": 1
        },
        "gross": {
          "key": 1
        },
        "invoices": 1
      }
    ],
    "byDirection": [
      {
        "direction": "string",
        "count": 1
      }
    ],
    "co2ByMode": [
      {
        "mode": "string",
        "kg": 1,
        "shipments": 1
      }
    ],
    "topRoutes": [
      {
        "originCode": null,
        "destinationCode": null,
        "count": 1
      }
    ],
    "currencies": [
      "string"
    ],
    "co2Rows": [
      {
        "shipmentId": "string",
        "referenceNumber": "string",
        "mode": "string",
        "originCode": null,
        "destinationCode": null,
        "distanceKm": null,
        "tonnes": null,
        "basis": null,
        "factor": null,
        "kg": null,
        "reason": null
      }
    ]
  },
  "coverage": {
    "shipments": 1,
    "undated": 1,
    "airWithoutWeight": 1,
    "lclWithoutVolume": 1,
    "containersUnknownType": 1,
    "co2NotEstimated": 1
  },
  "empty": true,
  "source": "listForReports"
}
```

**400** – Invalid period

Content-Type: `application/json`

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

**401** – No customer session

Content-Type: `application/json`

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

**403** – Missing reports area or portal.reports.view

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_reports/portal/summary?groupBy=month" \
  -H "Accept: application/json"
```

## GET `/gt_shipments/maplibre/{file}`

MapLibre GL worker module (static library file for the portal map)

**Tags:** GT Shipments

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

### Responses

**200** – JavaScript module

Content-Type: `application/json`

```json
"string"
```

**404** – Unknown file

Content-Type: `application/json`

```json
"string"
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/maplibre/:file" \
  -H "Accept: application/json"
```

## GET `/gt_shipments/portal/export`

Export the current shipments view as CSV

**Tags:** GT Shipments

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| direction | query | any | Optional |
| view | query | any | Optional |
| search | query | any | Optional |
| filter | query | any | Optional |
| mode | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – CSV file

Content-Type: `application/json`

```json
"string"
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/portal/export?direction=import&view=all" \
  -H "Accept: application/json"
```

## GET `/gt_shipments/portal/goods`

Customer goods (packing-list items) grouped by SKU and by shipment

**Tags:** GT Shipments

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

### Responses

**200** – Goods

Content-Type: `application/json`

```json
{
  "ok": true,
  "products": [
    {}
  ],
  "shipments": [
    {}
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/portal/goods" \
  -H "Accept: application/json"
```

## GET `/gt_shipments/portal/map`

Active customer shipments with map geometry (position, travelled/remaining route)

**Tags:** GT Shipments

### Responses

**200** – Active shipments

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {}
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/portal/map" \
  -H "Accept: application/json"
```

## GET `/gt_shipments/portal/shipments`

Customer shipments (current company) with view counts

**Tags:** GT Shipments

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| direction | query | any | Optional |
| view | query | any | Optional |
| search | query | any | Optional |
| filter | query | any | Optional |
| mode | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Shipments page

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "string",
      "referenceNumber": "string",
      "direction": "string",
      "transportMode": null,
      "statusCode": "string",
      "primaryReference": null,
      "eta": null,
      "etd": null,
      "etaDeviationDays": null,
      "holdPresent": true
    }
  ],
  "total": 1,
  "totalPages": 1,
  "counts": {
    "key": 1
  }
}
```

**401** – No customer session

Content-Type: `application/json`

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

**403** – Role or company area does not allow shipments

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/portal/shipments?direction=import&view=all&page=1&pageSize=50" \
  -H "Accept: application/json"
```

## GET `/gt_shipments/portal/shipments/{id}`

Customer shipment detail (teczka): units, legs, items, timeline

**Tags:** GT Shipments

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

### Responses

**200** – Shipment detail

Content-Type: `application/json`

```json
{
  "ok": true,
  "shipment": {},
  "units": [
    {}
  ],
  "timeline": [
    {}
  ]
}
```

**404** – Not found for this company

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/portal/shipments/:id" \
  -H "Accept: application/json"
```

## POST `/gt_shipments/reproject`

Re-project portal shipments from cached FMS folders

Requires features: gt_shipments.manage

**Tags:** GT Shipments

**Requires authentication.**

**Features:** gt_shipments.manage

### Responses

**200** – Projection stats

Content-Type: `application/json`

```json
{
  "ok": true,
  "total": 1,
  "projected": 1,
  "deleted": 1,
  "skipped": 1
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/gt_shipments/reproject" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/gt_shipments/shipments`

List projected portal shipments (staff diagnostics, incl. unmatched)

Requires features: gt_shipments.view

**Tags:** GT Shipments

**Requires authentication.**

**Features:** gt_shipments.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| search | query | any | Optional |
| matched | query | any | Optional |
| companyId | query | any | Optional |
| statusCode | query | any | Optional |

### Responses

**200** – Shipments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "referenceNumber": "string",
      "customerCompanyId": null,
      "statusCode": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/gt_shipments/shipments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations`

List integrations

Returns a paginated collection of integrations.

Requires features: integrations.view

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Optional |
| category | query | any | Optional |
| bundleId | query | any | Optional |
| isEnabled | query | any | Optional |
| healthStatus | query | any | Optional |
| sort | query | any | Optional |
| order | 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 integrations

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "description": null,
      "category": null,
      "tags": [
        "string"
      ],
      "hub": null,
      "providerKey": null,
      "bundleId": null,
      "author": null,
      "company": null,
      "version": null,
      "hasCredentials": true,
      "isEnabled": true,
      "apiVersion": null,
      "healthStatus": "healthy",
      "lastHealthCheckedAt": null,
      "lastHealthLatencyMs": null,
      "enabledAt": null,
      "analytics": {
        "lastActivityAt": null,
        "totalCount": 1,
        "errorCount": 1,
        "errorRate": 1,
        "dailyCounts": [
          1
        ]
      }
    }
  ],
  "total": 1,
  "totalPages": 1,
  "bundles": [
    {
      "id": "string",
      "title": "string",
      "description": "string",
      "icon": null,
      "integrationCount": 1,
      "enabledCount": 1
    }
  ]
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/integrations?order=asc&page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/{id}`

Get integration detail

Requires features: integrations.view

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/integrations/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/integrations/{id}/credentials`

Get, save, or delete integration credentials

Requires features: integrations.credentials.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.credentials.manage

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/{id}/credentials`

Get, save, or delete integration credentials

Requires features: integrations.credentials.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.credentials.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/credentials`

Get, save, or delete integration credentials

Requires features: integrations.credentials.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.credentials.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/integrations/{id}/health`

Run health check for an integration

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/integrations/:id/health" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/state`

Update integration state

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/integrations/:id/state" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/version`

Change integration API version

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/integrations/:id/version" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/logs`

List integration logs

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/integrations/logs" \
  -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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/notifications/unread-count" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/access-delegations`

GET /one_record/access-delegations

Requires features: one_record.access_grants.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.access_grants.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/access-delegations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/one_record/access-delegations`

POST /one_record/access-delegations

Requires features: one_record.access_grants.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.access_grants.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/access-delegations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/one_record/access-delegations/{id}`

PATCH /one_record/access-delegations/{id}

Requires features: one_record.access_grants.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.access_grants.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/one_record/access-delegations/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/one_record/access-delegations/{id}`

PUT /one_record/access-delegations/{id}

Requires features: one_record.access_grants.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.access_grants.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/one_record/access-delegations/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/one_record/action-requests/{id}`

DELETE /one_record/action-requests/{id}

Requires features: one_record.objects.publish

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.objects.publish

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/one_record/action-requests/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/action-requests/{id}`

GET /one_record/action-requests/{id}

**Tags:** ONE Record

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/action-requests/:id" \
  -H "Accept: application/json"
```

## PATCH `/one_record/action-requests/{id}`

PATCH /one_record/action-requests/{id}

Requires features: one_record.objects.publish

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.objects.publish

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/one_record/action-requests/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/config`

GET /one_record/config

Requires features: one_record.settings.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.settings.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/config" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/one_record/config`

PUT /one_record/config

Requires features: one_record.settings.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.settings.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/one_record/config" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/deliveries`

GET /one_record/deliveries

Requires features: one_record.subscriptions.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.subscriptions.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/deliveries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/one_record/deliveries/{id}`

POST /one_record/deliveries/{id}

Requires features: one_record.subscriptions.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.subscriptions.manage

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/deliveries/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/logistics-objects`

GET /one_record/logistics-objects

**Tags:** ONE Record

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/logistics-objects" \
  -H "Accept: application/json"
```

## GET `/one_record/logistics-objects/{id}`

GET /one_record/logistics-objects/{id}

**Tags:** ONE Record

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/logistics-objects/:id" \
  -H "Accept: application/json"
```

## PATCH `/one_record/logistics-objects/{id}`

PATCH /one_record/logistics-objects/{id}

**Tags:** ONE Record

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/one_record/logistics-objects/:id" \
  -H "Accept: application/json"
```

## GET `/one_record/logistics-objects/{id}/audit-trail`

GET /one_record/logistics-objects/{id}/audit-trail

Requires features: one_record.objects.view

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.objects.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/logistics-objects/:id/audit-trail" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/logistics-objects/{id}/content`

GET /one_record/logistics-objects/{id}/content

**Tags:** ONE Record

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/logistics-objects/:id/content" \
  -H "Accept: application/json"
```

## GET `/one_record/logistics-objects/{id}/logistics-events`

GET /one_record/logistics-objects/{id}/logistics-events

**Tags:** ONE Record

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/logistics-objects/:id/logistics-events" \
  -H "Accept: application/json"
```

## GET `/one_record/logistics-objects/{id}/logistics-events/{eventId}`

GET /one_record/logistics-objects/{id}/logistics-events/{eventId}

**Tags:** ONE Record

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/logistics-objects/:id/logistics-events/:eventId" \
  -H "Accept: application/json"
```

## POST `/one_record/notifications`

POST /one_record/notifications

**Tags:** ONE Record

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/notifications" \
  -H "Accept: application/json"
```

## POST `/one_record/notifications/{peerId}`

POST /one_record/notifications/{peerId}

**Tags:** ONE Record

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/notifications/:peerId" \
  -H "Accept: application/json"
```

## GET `/one_record/oauth/jwks`

GET /one_record/oauth/jwks

**Tags:** ONE Record

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/oauth/jwks" \
  -H "Accept: application/json"
```

## GET `/one_record/oauth/metadata`

GET /one_record/oauth/metadata

**Tags:** ONE Record

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/oauth/metadata" \
  -H "Accept: application/json"
```

## POST `/one_record/oauth/token`

POST /one_record/oauth/token

**Tags:** ONE Record

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/oauth/token" \
  -H "Accept: application/json"
```

## DELETE `/one_record/peer-subscriptions`

DELETE /one_record/peer-subscriptions

**Tags:** ONE Record

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/one_record/peer-subscriptions" \
  -H "Accept: application/json"
```

## GET `/one_record/peer-subscriptions`

GET /one_record/peer-subscriptions

**Tags:** ONE Record

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/peer-subscriptions" \
  -H "Accept: application/json"
```

## POST `/one_record/peer-subscriptions`

POST /one_record/peer-subscriptions

**Tags:** ONE Record

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/peer-subscriptions" \
  -H "Accept: application/json"
```

## GET `/one_record/peers`

GET /one_record/peers

Requires features: one_record.peers.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.peers.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/peers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/one_record/peers`

POST /one_record/peers

Requires features: one_record.peers.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.peers.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/peers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/one_record/resolve`

GET /one_record/resolve

**Tags:** ONE Record

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/resolve" \
  -H "Accept: application/json"
```

## GET `/one_record/server-information`

GET /one_record/server-information

**Tags:** ONE Record

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/server-information" \
  -H "Accept: application/json"
```

## GET `/one_record/subscriptions`

GET /one_record/subscriptions

Requires features: one_record.subscriptions.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.subscriptions.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/one_record/subscriptions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/one_record/subscriptions`

POST /one_record/subscriptions

Requires features: one_record.subscriptions.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.subscriptions.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/one_record/subscriptions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/one_record/subscriptions/{id}`

PATCH /one_record/subscriptions/{id}

Requires features: one_record.subscriptions.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.subscriptions.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://portal.gt.freighttech.org/api/one_record/subscriptions/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/one_record/subscriptions/{id}`

PUT /one_record/subscriptions/{id}

Requires features: one_record.subscriptions.manage

**Tags:** ONE Record

**Requires authentication.**

**Features:** one_record.subscriptions.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/one_record/subscriptions/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/perspectives/{tableId}`

Load perspectives for a table

Returns personal perspectives and available role defaults for the requested table identifier.

Requires features: perspectives.use

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.use

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

### Responses

**200** – Current perspectives and defaults.

Content-Type: `application/json`

```json
{
  "tableId": "string",
  "perspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null
    }
  ],
  "defaultPerspectiveId": null,
  "rolePerspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null,
      "roleId": "00000000-0000-4000-8000-000000000000",
      "tenantId": null,
      "organizationId": null,
      "roleName": null
    }
  ],
  "manageableRolePerspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null,
      "roleId": "00000000-0000-4000-8000-000000000000",
      "tenantId": null,
      "organizationId": null,
      "roleName": null
    }
  ],
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPerspective": true,
      "hasDefault": true
    }
  ],
  "canApplyToRoles": true
}
```

**400** – Invalid table identifier

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/perspectives/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/perspectives/{tableId}`

Create or update a perspective

Saves a personal perspective and optionally applies the same configuration to selected roles.

Requires features: perspectives.use

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.use

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Perspective saved successfully.

Content-Type: `application/json`

```json
{
  "perspective": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "tableId": "string",
    "settings": {},
    "isDefault": true,
    "createdAt": "string",
    "updatedAt": null
  },
  "rolePerspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null,
      "roleId": "00000000-0000-4000-8000-000000000000",
      "tenantId": null,
      "organizationId": null,
      "roleName": null
    }
  ],
  "clearedRoleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

**400** – Validation failed or invalid roles provided

Content-Type: `application/json`

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

**409** – Optimistic lock conflict or perspective name already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/perspectives/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"settings\": {}
}"
```

## DELETE `/perspectives/{tableId}/{perspectiveId}`

Delete a personal perspective

Removes a perspective owned by the current user for the given table.

Requires features: perspectives.use

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.use

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |
| perspectiveId | path | any | Required |

### Responses

**200** – Perspective removed.

Content-Type: `application/json`

```json
{
  "success": true
}
```

**400** – Invalid identifiers supplied

Content-Type: `application/json`

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

**404** – Perspective not found

Content-Type: `application/json`

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

**409** – Optimistic lock conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/perspectives/string/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/perspectives/{tableId}/roles/{roleId}`

Clear role perspectives for a table

Removes all role-level perspectives associated with the provided role identifier for the table.

Requires features: perspectives.role_defaults

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.role_defaults

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |
| roleId | path | any | Required |

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**200** – Role perspectives cleared.

Content-Type: `application/json`

```json
{
  "success": true
}
```

**400** – Invalid identifiers supplied

Content-Type: `application/json`

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

**404** – Role not found in scope

Content-Type: `application/json`

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

**409** – Optimistic lock conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/perspectives/string/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/progress/active`

GET /progress/active

Requires features: progress.view

**Tags:** Progress

**Requires authentication.**

**Features:** progress.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/progress/active" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/progress/jobs`

List progressjobs

Returns a paginated collection of progressjobs scoped to the authenticated tenant.

Requires features: progress.view

**Tags:** Progress

**Requires authentication.**

**Features:** progress.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| status | query | any | Optional |
| jobType | query | any | Optional |
| parentJobId | query | any | Optional |
| includeCompleted | query | any | Optional |
| completedSince | query | any | Optional |
| 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 progressjobs

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "jobType": "string",
      "name": "string",
      "description": null,
      "status": "string",
      "progressPercent": 1,
      "processedCount": 1,
      "totalCount": null,
      "etaSeconds": null,
      "cancellable": true,
      "startedAt": null,
      "finishedAt": null,
      "errorMessage": null,
      "createdAt": null,
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/progress/jobs?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/progress/jobs`

Create progressjob

Creates a new progress job for tracking a long-running operation.

Requires features: progress.create

**Tags:** Progress

**Requires authentication.**

**Features:** progress.create

### Request Body

Content-Type: `application/json`

```json
{
  "jobType": "string",
  "name": "string",
  "cancellable": false
}
```

### Responses

**201** – ProgressJob created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://portal.gt.freighttech.org/api/progress/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"jobType\": \"string\",
  \"name\": \"string\",
  \"cancellable\": false
}"
```

## DELETE `/progress/jobs/{id}`

DELETE /progress/jobs/{id}

Requires features: progress.cancel

**Tags:** Progress

**Requires authentication.**

**Features:** progress.cancel

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://portal.gt.freighttech.org/api/progress/jobs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/progress/jobs/{id}`

GET /progress/jobs/{id}

Requires features: progress.view

**Tags:** Progress

**Requires authentication.**

**Features:** progress.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/progress/jobs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/progress/jobs/{id}`

PUT /progress/jobs/{id}

Requires features: progress.update

**Tags:** Progress

**Requires authentication.**

**Features:** progress.update

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://portal.gt.freighttech.org/api/progress/jobs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/query_index/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/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://portal.gt.freighttech.org/api/scheduler/trigger" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## GET `/version`

Deployed Open Mercato version

**Tags:** API Documentation

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://portal.gt.freighttech.org/api/version" \
  -H "Accept: application/json"
```