forked from fa/breadcrumb-the-shire
1632 lines
42 KiB
YAML
1632 lines
42 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Malphite API
|
|
version: v1
|
|
description: |
|
|
OpenAPI specification for the current `/api/v1` endpoints.
|
|
Authentication uses Bearer tokens in the format `<selector>:<token>`.
|
|
servers:
|
|
- url: /api/v1
|
|
security:
|
|
- BearerAuth: []
|
|
tags:
|
|
- name: auth
|
|
description: Public authentication endpoints (no Bearer token required)
|
|
- name: me
|
|
- name: tokens
|
|
- name: users
|
|
- name: tenants
|
|
- name: departments
|
|
- name: roles
|
|
paths:
|
|
/auth/login:
|
|
post:
|
|
tags: [auth]
|
|
summary: Login with email and password
|
|
description: |
|
|
Authenticates a user with email and password and returns a Bearer token.
|
|
This endpoint is **public** — no Authorization header required.
|
|
|
|
The returned token can be used immediately as `Authorization: Bearer <token>`
|
|
for all subsequent API requests.
|
|
|
|
Rate limits (stricter than general API limits):
|
|
- 10 failed attempts per IP per 10 minutes
|
|
- 5 failed attempts per email+IP per 15 minutes
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginRequest'
|
|
example:
|
|
email: user@example.com
|
|
password: "..."
|
|
token_name: "My App"
|
|
responses:
|
|
'201':
|
|
description: Login successful — token issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginResponse'
|
|
'401':
|
|
description: Authentication failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
invalid_credentials:
|
|
value:
|
|
error: invalid_credentials
|
|
account_inactive:
|
|
value:
|
|
error: account_inactive
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'409':
|
|
$ref: '#/components/responses/Conflict'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me:
|
|
get:
|
|
tags: [me]
|
|
summary: Get authenticated user profile
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/MeResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens:
|
|
get:
|
|
tags: [tokens]
|
|
summary: List current user API tokens
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit50'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [tokens]
|
|
summary: Create API token for current user
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenCreateRequest'
|
|
responses:
|
|
'201':
|
|
description: Created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenCreateResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'409':
|
|
$ref: '#/components/responses/Conflict'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [tokens]
|
|
summary: Get current user token by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [tokens]
|
|
summary: Revoke current user token by UUID
|
|
responses:
|
|
'204':
|
|
description: No Content
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens/rotate:
|
|
post:
|
|
tags: [tokens]
|
|
summary: Rotate currently used API token
|
|
requestBody:
|
|
required: false
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
responses:
|
|
'201':
|
|
description: Created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TokenCreateResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
$ref: '#/components/responses/Conflict'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/me/tokens/revoke-all:
|
|
post:
|
|
tags: [tokens]
|
|
summary: Revoke all current user API tokens
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RevokeAllResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/users:
|
|
get:
|
|
tags: [users]
|
|
summary: List users
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderUsers'
|
|
- $ref: '#/components/parameters/Dir'
|
|
- $ref: '#/components/parameters/ActiveFilter'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [users]
|
|
summary: Create user
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserCreateRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/users/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [users]
|
|
summary: Get user by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [users]
|
|
summary: Update user by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserUpdateRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [users]
|
|
summary: Patch user by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserUpdateRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [users]
|
|
summary: Delete user by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/tenants:
|
|
get:
|
|
tags: [tenants]
|
|
summary: List tenants
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderTenants'
|
|
- $ref: '#/components/parameters/Dir'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [tenants]
|
|
summary: Create tenant
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantWriteRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/tenants/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [tenants]
|
|
summary: Get tenant by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [tenants]
|
|
summary: Update tenant by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [tenants]
|
|
summary: Patch tenant by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [tenants]
|
|
summary: Delete tenant by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/departments:
|
|
get:
|
|
tags: [departments]
|
|
summary: List departments
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderDepartments'
|
|
- $ref: '#/components/parameters/Dir'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [departments]
|
|
summary: Create department
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentWriteRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/departments/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [departments]
|
|
summary: Get department by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [departments]
|
|
summary: Update department by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [departments]
|
|
summary: Patch department by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/DepartmentWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [departments]
|
|
summary: Delete department by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/roles:
|
|
get:
|
|
tags: [roles]
|
|
summary: List roles
|
|
parameters:
|
|
- $ref: '#/components/parameters/Limit25'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/Search'
|
|
- $ref: '#/components/parameters/OrderRoles'
|
|
- $ref: '#/components/parameters/Dir'
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
post:
|
|
tags: [roles]
|
|
summary: Create role
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleWriteRequest'
|
|
responses:
|
|
'201':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
/roles/show/{uuid}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/UuidPath'
|
|
get:
|
|
tags: [roles]
|
|
summary: Get role by UUID
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleShowResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
put:
|
|
tags: [roles]
|
|
summary: Update role by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
patch:
|
|
tags: [roles]
|
|
summary: Patch role by UUID
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoleWriteRequest'
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'422':
|
|
$ref: '#/components/responses/ValidationError'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
delete:
|
|
tags: [roles]
|
|
summary: Delete role by UUID
|
|
responses:
|
|
'200':
|
|
$ref: '#/components/responses/DataObject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'429':
|
|
$ref: '#/components/responses/RateLimited'
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: selector:token
|
|
parameters:
|
|
UuidPath:
|
|
name: uuid
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
Limit25:
|
|
name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 25
|
|
Limit50:
|
|
name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 50
|
|
Offset:
|
|
name: offset
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 0
|
|
default: 0
|
|
Search:
|
|
name: search
|
|
in: query
|
|
schema:
|
|
type: string
|
|
Dir:
|
|
name: dir
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [asc, desc]
|
|
default: asc
|
|
ActiveFilter:
|
|
name: active
|
|
in: query
|
|
schema:
|
|
type: string
|
|
description: "Accepted aliases: 1, 0, true, false, active, inactive"
|
|
OrderUsers:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, first_name, last_name, display_name, email, created, modified, active, last_login_at]
|
|
default: last_name
|
|
OrderTenants:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, description, created, modified]
|
|
default: description
|
|
OrderDepartments:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, description, code, cost_center, active, created, modified]
|
|
default: description
|
|
OrderRoles:
|
|
name: order
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [id, uuid, description, code, active, created, modified]
|
|
default: description
|
|
responses:
|
|
Unauthorized:
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
error: unauthorized
|
|
Forbidden:
|
|
description: Forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
NotFound:
|
|
description: Not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
error: not_found
|
|
ValidationError:
|
|
description: Validation failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
error: validation_error
|
|
errors:
|
|
field:
|
|
- invalid_value
|
|
Conflict:
|
|
description: Conflict
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
RateLimited:
|
|
description: Rate limited
|
|
headers:
|
|
Retry-After:
|
|
schema:
|
|
type: integer
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
error: rate_limit_exceeded
|
|
ServerError:
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
DataObject:
|
|
description: Generic service response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/GenericDataResponse'
|
|
schemas:
|
|
ErrorResponse:
|
|
type: object
|
|
required: [error]
|
|
properties:
|
|
error:
|
|
type: string
|
|
errors:
|
|
type: object
|
|
additionalProperties:
|
|
type: array
|
|
items:
|
|
type: string
|
|
GenericDataResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
additionalProperties: true
|
|
LoginRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [email, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
description: User email address (case-insensitive)
|
|
password:
|
|
type: string
|
|
description: User password
|
|
token_name:
|
|
type: string
|
|
description: Optional label for the issued token (e.g. "iPhone App"). Defaults to "Login".
|
|
default: Login
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
description: Optional — scope the issued token to a specific tenant UUID. Must be assigned to the user.
|
|
LoginResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
required: [token, token_uuid, expires_at]
|
|
properties:
|
|
token:
|
|
type: string
|
|
description: Full Bearer token in format `selector:plaintext`. Shown only once — store securely.
|
|
example: "abc123def:456789..."
|
|
token_uuid:
|
|
type: string
|
|
format: uuid
|
|
description: UUID of the created token record (use for revocation via /me/tokens)
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
description: UTC expiry timestamp of the token
|
|
RoleWriteRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [description]
|
|
properties:
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
code:
|
|
type: string
|
|
active:
|
|
type: string
|
|
description: "Accepted aliases: 1, 0, true, false, active, inactive"
|
|
DepartmentWriteRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [description, tenant_id]
|
|
properties:
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
tenant_id:
|
|
type: integer
|
|
minimum: 1
|
|
code:
|
|
type: string
|
|
cost_center:
|
|
type: string
|
|
active:
|
|
type: string
|
|
description: "Accepted aliases: 1, 0, true, false, active, inactive"
|
|
TenantWriteRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [description, status]
|
|
properties:
|
|
description:
|
|
type: string
|
|
minLength: 1
|
|
status:
|
|
type: string
|
|
enum: [active, inactive]
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
vat_id:
|
|
type: string
|
|
tax_number:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
fax:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
support_email:
|
|
type: string
|
|
format: email
|
|
support_phone:
|
|
type: string
|
|
billing_email:
|
|
type: string
|
|
format: email
|
|
website:
|
|
type: string
|
|
privacy_url:
|
|
type: string
|
|
imprint_url:
|
|
type: string
|
|
primary_color:
|
|
type: string
|
|
description: "Hex color, e.g. #0f766e"
|
|
primary_color_use_default:
|
|
type: boolean
|
|
default_theme:
|
|
type: string
|
|
allow_user_theme_mode:
|
|
type: string
|
|
enum: ['', '0', '1']
|
|
UserCreateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [first_name, last_name, email, password, password2]
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
minLength: 1
|
|
last_name:
|
|
type: string
|
|
minLength: 1
|
|
email:
|
|
type: string
|
|
format: email
|
|
profile_description:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
hire_date:
|
|
type: string
|
|
format: date
|
|
locale:
|
|
type: string
|
|
theme:
|
|
type: string
|
|
totp_secret:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
password:
|
|
type: string
|
|
password2:
|
|
type: string
|
|
tenant_ids:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
minimum: 1
|
|
primary_tenant_id:
|
|
type: integer
|
|
minimum: 1
|
|
role_ids:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
minimum: 1
|
|
department_ids:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
minimum: 1
|
|
UserUpdateRequest:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [first_name, last_name, email]
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
minLength: 1
|
|
last_name:
|
|
type: string
|
|
minLength: 1
|
|
email:
|
|
type: string
|
|
format: email
|
|
profile_description:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
hire_date:
|
|
type: string
|
|
format: date
|
|
locale:
|
|
type: string
|
|
theme:
|
|
type: string
|
|
totp_secret:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
password:
|
|
type: string
|
|
password2:
|
|
type: string
|
|
tenant_ids:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
minimum: 1
|
|
primary_tenant_id:
|
|
type: integer
|
|
minimum: 1
|
|
role_ids:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
minimum: 1
|
|
department_ids:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
minimum: 1
|
|
TenantSummary:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
status:
|
|
type: string
|
|
AssignmentDepartment:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
AssignmentRole:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
Assignments:
|
|
type: object
|
|
properties:
|
|
tenants:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
departments:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AssignmentDepartment'
|
|
roles:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AssignmentRole'
|
|
UserCustomFieldOption:
|
|
type: object
|
|
properties:
|
|
option_key:
|
|
type: string
|
|
label:
|
|
type: string
|
|
UserCustomFieldField:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
field_key:
|
|
type: string
|
|
label:
|
|
type: string
|
|
type:
|
|
type: string
|
|
is_filterable:
|
|
type: boolean
|
|
value:
|
|
description: Type-dependent value (string, boolean, null, or array of option keys).
|
|
options:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldOption'
|
|
UserCustomFieldTenantGroup:
|
|
type: object
|
|
properties:
|
|
tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
fields:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldField'
|
|
MeResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
locale:
|
|
type: string
|
|
current_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
primary_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
can_view_permissions:
|
|
type: boolean
|
|
permissions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
assignments:
|
|
$ref: '#/components/schemas/Assignments'
|
|
custom_fields:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldTenantGroup'
|
|
TokenItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
selector_prefix:
|
|
type: string
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
last_used_at:
|
|
type: string
|
|
nullable: true
|
|
last_ip:
|
|
type: string
|
|
expires_at:
|
|
type: string
|
|
nullable: true
|
|
revoked_at:
|
|
type: string
|
|
nullable: true
|
|
created:
|
|
type: string
|
|
nullable: true
|
|
is_current_token:
|
|
type: boolean
|
|
TokenListResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TokenItem'
|
|
limit:
|
|
type: integer
|
|
TokenShowResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
$ref: '#/components/schemas/TokenItem'
|
|
TokenCreateRequest:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
TokenCreateResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
token_uuid:
|
|
type: string
|
|
format: uuid
|
|
token:
|
|
type: string
|
|
selector_prefix:
|
|
type: string
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
expires_at:
|
|
type: string
|
|
nullable: true
|
|
RevokeAllResponse:
|
|
type: object
|
|
required: [data]
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
revoked_count:
|
|
type: integer
|
|
tenant_uuid:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
UserListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
tenants:
|
|
type: array
|
|
items:
|
|
type: string
|
|
departments:
|
|
type: array
|
|
items:
|
|
type: string
|
|
roles:
|
|
type: array
|
|
items:
|
|
type: string
|
|
UserListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
UserShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
display_name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
job_title:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
mobile:
|
|
type: string
|
|
short_dial:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|
|
primary_tenant:
|
|
$ref: '#/components/schemas/TenantSummary'
|
|
permissions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
assignments:
|
|
$ref: '#/components/schemas/Assignments'
|
|
custom_fields:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/UserCustomFieldTenantGroup'
|
|
TenantListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
status:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
created:
|
|
type: string
|
|
TenantListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TenantListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
TenantShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
status:
|
|
type: string
|
|
address:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
city:
|
|
type: string
|
|
country:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
email:
|
|
type: string
|
|
website:
|
|
type: string
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|
|
DepartmentListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
tenant_labels:
|
|
type: array
|
|
items:
|
|
type: string
|
|
created:
|
|
type: string
|
|
DepartmentListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/DepartmentListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
DepartmentShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
tenant_id:
|
|
type: integer
|
|
nullable: true
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|
|
RoleListItem:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
RoleListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/RoleListItem'
|
|
total:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
offset:
|
|
type: integer
|
|
RoleShowResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
properties:
|
|
uuid:
|
|
type: string
|
|
format: uuid
|
|
description:
|
|
type: string
|
|
code:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created:
|
|
type: string
|
|
modified:
|
|
type: string
|