- Extend `users_o` and `subusers_o` with `two_factor_enabled` and `two_factor_secret` properties. - Implement methods for managing 2FA (`isTwoFactorEnabled`, `setTwoFactorSecret`, `verify_2fa_code`) in authentication logic. - Add 2FA handling in login flows for both users and subusers, including token generation and validation. - Introduce `totp` class for TOTP-based authentication, including QR code generation and code verification. - Add test cases for 2FA functionality (`TwoFactorAuthTest.php`) and coverage for login scenarios with 2FA. - Update OpenAPI specifications to include 2FA flows (`auth/2fa/setup`, `auth/2fa/enable`, `auth/2fa/verify`, `auth/2fa/disable`).
8287 lines
229 KiB
YAML
8287 lines
229 KiB
YAML
openapi: 3.0.3
|
||
info:
|
||
title: Copenhagen Truck Wash API
|
||
description: |
|
||
This API provides access to the Copenhagen Truck Wash system, managing orders, bookings,
|
||
departments, products, customers, and various integrations including e-conomic, Stripe,
|
||
XLVask, and more.
|
||
|
||
## Authentication
|
||
Most endpoints require authentication using a Bearer token obtained from the `/auth/login`
|
||
or `/auth/employee/login` endpoints.
|
||
|
||
## Permissions
|
||
Many endpoints require specific permissions that are assigned to user groups/roles.
|
||
|
||
## Subusers and customer targeting
|
||
When authenticated as a subuser, most customer-scoped endpoints require an explicit target
|
||
customer context. Provide the header `X-Customer-Number: <customer_number>` to target a
|
||
specific customer. If omitted, the API attempts to infer the customer from the authenticated
|
||
user context when possible. Classic user sessions ignore this header.
|
||
version: 1.0.0
|
||
contact:
|
||
name: Copenhagen Truck Wash
|
||
email: support@truckwash.dk
|
||
servers:
|
||
- url: https://api.truckwash.dk
|
||
description: Production server
|
||
- url: http://localhost
|
||
description: Local development server
|
||
|
||
security:
|
||
- BearerAuth: []
|
||
|
||
tags:
|
||
- name: Authentication
|
||
description: User and employee authentication endpoints
|
||
- name: Users
|
||
description: User management and customer operations
|
||
- name: Orders
|
||
description: Order creation, management, and retrieval
|
||
- name: Order Items
|
||
description: Managing items within orders
|
||
- name: Bookings
|
||
description: Booking management for wash services
|
||
- name: Departments
|
||
description: Department and location management
|
||
- name: Products
|
||
description: Product catalog and pricing
|
||
- name: Categories
|
||
description: Product category management
|
||
- name: Invoices
|
||
description: Invoice generation and management
|
||
- name: Payments
|
||
description: Payment processing and collection
|
||
- name: Vehicles
|
||
description: Vehicle registration and management
|
||
- name: Notifications
|
||
description: System notifications and alerts
|
||
- name: Statistics
|
||
description: Business analytics and reporting
|
||
- name: Modules
|
||
description: Third-party integrations and modules
|
||
- name: Attachments
|
||
description: File upload and attachment management
|
||
- name: Forms
|
||
description: Form submissions and management
|
||
- name: Worker
|
||
description: System worker status and maintenance
|
||
- name: Plate Scans
|
||
description: License plate scanning operations
|
||
- name: Config
|
||
description: Module configuration management
|
||
- name: Branding
|
||
description: Branding options management
|
||
- name: Roles
|
||
description: Role and permission management
|
||
- name: Self-Serve
|
||
description: Self-serve lane operations and questions
|
||
- name: Goals
|
||
description: Department goals management
|
||
- name: Subusers
|
||
description: Subuser registration and setup
|
||
- name: Bird
|
||
description: Voice Calls via Bird
|
||
|
||
paths:
|
||
# Bird Voice Calls
|
||
/bird/voice/calls:
|
||
post:
|
||
tags:
|
||
- Bird
|
||
summary: Create/place a voice call via Bird
|
||
operationId: birdCreateVoiceCall
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
properties:
|
||
to:
|
||
type: string
|
||
description: E.164 phone number of the callee
|
||
example: "+4511122233"
|
||
from:
|
||
type: string
|
||
description: E.164 phone number of the caller (sender)
|
||
example: "+4599988877"
|
||
responses:
|
||
'200':
|
||
description: Call created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
get:
|
||
tags:
|
||
- Bird
|
||
summary: List voice calls
|
||
operationId: birdListVoiceCalls
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
required: false
|
||
responses:
|
||
'200':
|
||
description: A list of calls
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
/bird/voice/calls/{id}:
|
||
get:
|
||
tags:
|
||
- Bird
|
||
summary: Get a voice call by ID
|
||
operationId: birdGetVoiceCall
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Call details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
/bird/voice/calls/{id}/hangup:
|
||
post:
|
||
tags:
|
||
- Bird
|
||
summary: Hang up a voice call by ID
|
||
operationId: birdHangupVoiceCall
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Hangup requested
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
# Bird Numbers
|
||
/bird/numbers:
|
||
get:
|
||
tags:
|
||
- Bird
|
||
summary: List your numbers
|
||
operationId: birdListNumbers
|
||
parameters:
|
||
- in: query
|
||
name: page
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
- in: query
|
||
name: limit
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: A list of numbers
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
# Bird Voice Flash Calling
|
||
/bird/voice/flash-calls:
|
||
post:
|
||
tags:
|
||
- Bird
|
||
summary: Create/place a flash call via Bird
|
||
operationId: birdCreateFlashCall
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
responses:
|
||
'200':
|
||
description: Flash call created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
get:
|
||
tags:
|
||
- Bird
|
||
summary: List flash calls
|
||
operationId: birdListFlashCalls
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
- in: query
|
||
name: page
|
||
schema:
|
||
type: integer
|
||
required: false
|
||
responses:
|
||
'200':
|
||
description: A list of flash calls
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
/bird/voice/flash-calls/{id}:
|
||
get:
|
||
tags:
|
||
- Bird
|
||
summary: Get a flash call by ID
|
||
operationId: birdGetFlashCall
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Flash call details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
post:
|
||
tags:
|
||
- Bird
|
||
summary: Complete/end a flash call by ID
|
||
description: Posts a completion/update payload to the flash call resource to finalize verification.
|
||
operationId: birdEndFlashCall
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: string
|
||
requestBody:
|
||
required: false
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
responses:
|
||
'200':
|
||
description: Flash call completed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
/bird/voice/flash-calls/end:
|
||
post:
|
||
tags:
|
||
- Bird
|
||
summary: Complete/end a flash call using from/to numbers
|
||
description: Ends an ongoing flash call by specifying the originating and destination numbers.
|
||
operationId: birdEndFlashCallByNumbers
|
||
parameters:
|
||
- in: query
|
||
name: workspaceId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Workspace identifier
|
||
- in: query
|
||
name: channelId
|
||
schema:
|
||
type: string
|
||
required: true
|
||
description: Bird Channel identifier
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
properties:
|
||
from:
|
||
type: string
|
||
description: E.164 formatted caller number
|
||
example: "+4599988877"
|
||
to:
|
||
type: string
|
||
description: E.164 formatted callee number
|
||
example: "+4511122233"
|
||
responses:
|
||
'200':
|
||
description: Flash call completed (by numbers)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
# Subusers (public registration + setup)
|
||
/subusers:
|
||
get:
|
||
tags:
|
||
- Subusers
|
||
summary: List subusers visible to the authenticated user
|
||
description: |
|
||
Returns a paginated list of subusers (drivers) that have enabled grants tied to the
|
||
authenticated user's customer number. Only subusers with at least one enabled, non-deleted
|
||
grant for the caller's customer are returned.
|
||
operationId: listSubusers
|
||
parameters:
|
||
- name: page
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
- name: limit
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 1000
|
||
- name: search
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: string
|
||
- name: include_non_enabled
|
||
in: query
|
||
required: false
|
||
description: Include subusers that only have non-enabled grants (default false)
|
||
schema:
|
||
type: boolean
|
||
responses:
|
||
'200':
|
||
description: List of visible subusers
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
username:
|
||
type: string
|
||
nullable: true
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
email:
|
||
type: string
|
||
format: email
|
||
nullable: true
|
||
phone_country_code:
|
||
type: integer
|
||
nullable: true
|
||
phone:
|
||
type: integer
|
||
nullable: true
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
suspended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
permissions:
|
||
type: array
|
||
description: Aggregated permission keys granted for the caller's customer
|
||
items:
|
||
type: string
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/me:
|
||
get:
|
||
tags:
|
||
- Subusers
|
||
summary: Get current subuser profile
|
||
description: |
|
||
Returns the authenticated subuser (driver) profile and their enabled grants grouped by
|
||
`billing_customer_number`.
|
||
|
||
Notes:
|
||
- This endpoint is available only to authenticated subuser sessions.
|
||
- It does not require the `X-Customer-Number` header; all enabled, non-deleted grants for the
|
||
subuser are included in the response.
|
||
operationId: getCurrentSubuser
|
||
responses:
|
||
'200':
|
||
description: Current subuser details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SubuserSelf'
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
post:
|
||
tags:
|
||
- Subusers
|
||
summary: Create a subuser registration
|
||
description: |
|
||
Creates a subuser (driver) account using a company's CVR and a phone number. Validates the
|
||
CVR via e-conomic, ensures the phone number is not already in use, and if SMS is enabled
|
||
sends a setup link by SMS for the user to complete registration.
|
||
operationId: createSubuser
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- cvr
|
||
- phone_country_code
|
||
- phone
|
||
properties:
|
||
cvr:
|
||
type: integer
|
||
description: Danish CVR (8 digits)
|
||
example: 12345678
|
||
phone_country_code:
|
||
type: integer
|
||
description: Phone country code (1–3 digits)
|
||
example: 45
|
||
phone:
|
||
type: integer
|
||
description: Phone number (4–15 digits, no leading +)
|
||
example: 12345678
|
||
responses:
|
||
'200':
|
||
description: Subuser created (or pending setup) and company identified
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
cvr:
|
||
type: integer
|
||
example: 12345678
|
||
customer_number:
|
||
type: integer
|
||
description: Matched e-conomic customer number
|
||
example: 1000
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/{id}:
|
||
get:
|
||
tags:
|
||
- Subusers
|
||
summary: Get a subuser by ID (visible by grant)
|
||
description: |
|
||
Returns the subuser if the authenticated user has at least one enabled, non-deleted grant
|
||
for their customer number to this subuser. Otherwise returns 404.
|
||
operationId: getSubuser
|
||
parameters:
|
||
- name: id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Subuser details
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
username:
|
||
type: string
|
||
nullable: true
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
email:
|
||
type: string
|
||
format: email
|
||
nullable: true
|
||
phone_country_code:
|
||
type: integer
|
||
nullable: true
|
||
phone:
|
||
type: integer
|
||
nullable: true
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
suspended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
permissions:
|
||
type: array
|
||
description: Aggregated permission keys granted for the caller's customer
|
||
items:
|
||
type: string
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/setup:
|
||
get:
|
||
tags:
|
||
- Subusers
|
||
summary: Validate setup token
|
||
description: Validates a subuser setup token generated during registration.
|
||
operationId: validateSubuserSetupToken
|
||
security: []
|
||
parameters:
|
||
- name: token
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: One-time setup token received via SMS
|
||
responses:
|
||
'200':
|
||
description: Token is valid
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
example: Token is valid
|
||
subuser_id:
|
||
type: integer
|
||
example: 42
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
post:
|
||
tags:
|
||
- Subusers
|
||
summary: Complete subuser setup
|
||
description: |
|
||
Completes subuser setup by setting a password and basic profile fields. Accepts optional
|
||
`username` and `email`.
|
||
operationId: completeSubuserSetup
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- token
|
||
- password
|
||
- name
|
||
properties:
|
||
token:
|
||
type: string
|
||
description: One-time setup token
|
||
password:
|
||
type: string
|
||
format: password
|
||
minLength: 8
|
||
description: Must include at least one uppercase letter, one lowercase letter, and one number
|
||
pattern: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$'
|
||
name:
|
||
type: string
|
||
minLength: 3
|
||
maxLength: 255
|
||
username:
|
||
type: string
|
||
minLength: 3
|
||
maxLength: 255
|
||
email:
|
||
type: string
|
||
format: email
|
||
minLength: 3
|
||
maxLength: 255
|
||
responses:
|
||
'200':
|
||
description: Setup completed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
example: Password set successfully
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/auth/password:
|
||
post:
|
||
tags:
|
||
- Subusers
|
||
summary: Authenticate subuser with password
|
||
description: |
|
||
Authenticates a subuser (driver) using a password together with one of the supported
|
||
identifiers: `phone_country_code` + `phone`, `subuser_id`, or `username`.
|
||
|
||
On success, returns a newly generated session token for the subuser.
|
||
operationId: subuserPasswordAuth
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- type: object
|
||
required: [phone_country_code, phone, password]
|
||
properties:
|
||
phone_country_code:
|
||
type: integer
|
||
description: Phone country code (1–3 digits)
|
||
minimum: 1
|
||
maximum: 999
|
||
example: 45
|
||
phone:
|
||
type: integer
|
||
description: Phone number (4–15 digits, no leading +)
|
||
minimum: 1000
|
||
maximum: 999999999999999
|
||
example: 12345678
|
||
password:
|
||
type: string
|
||
format: password
|
||
minLength: 8
|
||
maxLength: 255
|
||
- type: object
|
||
required: [subuser_id, password]
|
||
properties:
|
||
subuser_id:
|
||
type: integer
|
||
description: Subuser ID
|
||
example: 42
|
||
password:
|
||
type: string
|
||
format: password
|
||
minLength: 8
|
||
maxLength: 255
|
||
- type: object
|
||
required: [username, password]
|
||
properties:
|
||
username:
|
||
type: string
|
||
minLength: 3
|
||
maxLength: 255
|
||
example: jdoe
|
||
password:
|
||
type: string
|
||
format: password
|
||
minLength: 8
|
||
maxLength: 255
|
||
examples:
|
||
withPhone:
|
||
summary: Authenticate with phone
|
||
value:
|
||
phone_country_code: 45
|
||
phone: 12345678
|
||
password: MySecureP@ssw0rd
|
||
withSubuserId:
|
||
summary: Authenticate with subuser_id
|
||
value:
|
||
subuser_id: 42
|
||
password: MySecureP@ssw0rd
|
||
withUsername:
|
||
summary: Authenticate with username
|
||
value:
|
||
username: jdoe
|
||
password: MySecureP@ssw0rd
|
||
responses:
|
||
'200':
|
||
description: Authentication successful
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- type: object
|
||
required: [session]
|
||
properties:
|
||
session:
|
||
type: string
|
||
description: Newly generated subuser session token
|
||
example: "2f7a8c0e-9b1d-4c6a-91a9-1a2b3c4d5e6f"
|
||
- type: object
|
||
required: [2fa_required, 2fa_token]
|
||
properties:
|
||
2fa_required:
|
||
type: boolean
|
||
example: true
|
||
2fa_token:
|
||
type: string
|
||
description: Temporary 2FA verification token
|
||
example: "557a3e7b1a2b..."
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/grants:
|
||
get:
|
||
tags:
|
||
- Subusers
|
||
summary: List subuser grants
|
||
description: Returns subuser grant records filtered by `customer_number` and/or `subuser_id`.
|
||
operationId: listSubuserGrants
|
||
security:
|
||
- BearerAuth: []
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
description: e-conomic customer number to filter by
|
||
- name: subuser_id
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
description: Subuser ID to filter by
|
||
responses:
|
||
'200':
|
||
description: Grants fetched
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
grants:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/SubuserGrant'
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
post:
|
||
tags:
|
||
- Subusers
|
||
summary: Create subuser grant
|
||
operationId: createSubuserGrant
|
||
security:
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SubuserGrantCreateRequest'
|
||
examples:
|
||
default:
|
||
value:
|
||
customer_number: 1000
|
||
subuser_id: 42
|
||
enabled: true
|
||
note: "Grant for bookings access"
|
||
permissions: ["BOOKINGS_LIST", "BOOKINGS_ADD", "BOOKINGS_EDIT"]
|
||
responses:
|
||
'200':
|
||
description: Grant created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
grant:
|
||
$ref: '#/components/schemas/SubuserGrant'
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/grants/{id}:
|
||
patch:
|
||
tags:
|
||
- Subusers
|
||
summary: Update subuser grant
|
||
operationId: updateSubuserGrant
|
||
security:
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SubuserGrantUpdateRequest'
|
||
examples:
|
||
enableOnly:
|
||
value:
|
||
enabled: true
|
||
updatePermissions:
|
||
value:
|
||
permissions: ["VEHICLES_LIST", "SELFSERVE_ADD"]
|
||
responses:
|
||
'200':
|
||
description: Grant updated
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
grant:
|
||
$ref: '#/components/schemas/SubuserGrant'
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
delete:
|
||
tags:
|
||
- Subusers
|
||
summary: Delete subuser grant
|
||
operationId: deleteSubuserGrant
|
||
security:
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Grant deleted
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
example: Grant deleted
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
/subusers/permission-nodes:
|
||
get:
|
||
tags:
|
||
- Subusers
|
||
summary: List available subuser permission nodes
|
||
description: Returns grouped permission nodes available for subuser grants.
|
||
operationId: listSubuserPermissionNodes
|
||
security:
|
||
- BearerAuth: []
|
||
responses:
|
||
'200':
|
||
description: Permission nodes fetched
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
permission_nodes:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/PermissionNodeGroup'
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
|
||
# Authentication Endpoints
|
||
/auth/login:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Customer login
|
||
description: Authenticate a customer using customer number and password
|
||
operationId: customerLogin
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- customer_number
|
||
- password
|
||
properties:
|
||
customer_number:
|
||
type: integer
|
||
description: Customer's e-conomic customer number
|
||
example: 12345
|
||
password:
|
||
type: string
|
||
format: password
|
||
description: Customer password
|
||
minLength: 1
|
||
responses:
|
||
'200':
|
||
description: Login successful
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- type: object
|
||
required: [token]
|
||
properties:
|
||
token:
|
||
type: string
|
||
description: Bearer authentication token
|
||
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||
- type: object
|
||
required: [2fa_required, 2fa_token]
|
||
properties:
|
||
2fa_required:
|
||
type: boolean
|
||
example: true
|
||
2fa_token:
|
||
type: string
|
||
description: Temporary 2FA verification token
|
||
example: "557a3e7b1a2b..."
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/employee/login:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Employee login
|
||
description: Authenticate an employee using user ID and password
|
||
operationId: employeeLogin
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- user_id
|
||
- password
|
||
properties:
|
||
user_id:
|
||
type: integer
|
||
description: Employee user ID
|
||
example: 1
|
||
password:
|
||
type: string
|
||
format: password
|
||
description: Employee password
|
||
responses:
|
||
'200':
|
||
description: Login successful
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- type: object
|
||
required: [token]
|
||
properties:
|
||
token:
|
||
type: string
|
||
description: Bearer authentication token
|
||
- type: object
|
||
required: [2fa_required, 2fa_token]
|
||
properties:
|
||
2fa_required:
|
||
type: boolean
|
||
example: true
|
||
2fa_token:
|
||
type: string
|
||
description: Temporary 2FA verification token
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/logout:
|
||
get:
|
||
tags:
|
||
- Authentication
|
||
summary: Logout
|
||
description: Invalidate the current authentication token
|
||
operationId: logout
|
||
responses:
|
||
'200':
|
||
description: Logout successful
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
example: "Logged out"
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/session:
|
||
get:
|
||
tags:
|
||
- Authentication
|
||
summary: Get current session
|
||
description: Retrieve information about the current authenticated user session
|
||
operationId: getSession
|
||
responses:
|
||
'200':
|
||
description: Session information retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/User'
|
||
- type: object
|
||
properties:
|
||
two_factor_enabled:
|
||
type: boolean
|
||
description: Indicates if 2FA is enabled for this account
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/2fa/setup:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Generate 2FA secret
|
||
description: Generate a new TOTP secret for the authenticated user/subuser
|
||
operationId: setup2fa
|
||
responses:
|
||
'200':
|
||
description: 2FA secret generated successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
secret:
|
||
type: string
|
||
description: The base32 encoded TOTP secret
|
||
qr_code_url:
|
||
type: string
|
||
description: An otpauth URL for generating a QR code
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/2fa/enable:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Enable 2FA
|
||
description: Verify a code and enable 2FA for the authenticated user/subuser
|
||
operationId: enable2fa
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [code]
|
||
properties:
|
||
code:
|
||
type: string
|
||
description: The 6-digit TOTP code
|
||
responses:
|
||
'200':
|
||
description: 2FA enabled successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/2fa/disable:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Disable 2FA
|
||
description: Verify a code and disable 2FA for the authenticated user/subuser
|
||
operationId: disable2fa
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [code]
|
||
properties:
|
||
code:
|
||
type: string
|
||
description: The 6-digit TOTP code
|
||
responses:
|
||
'200':
|
||
description: 2FA disabled successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/2fa/verify:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Verify 2FA code during login
|
||
description: Complete the login process by verifying the 2FA code
|
||
operationId: verify2fa
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [2fa_token, code]
|
||
properties:
|
||
2fa_token:
|
||
type: string
|
||
description: The temporary 2FA verification token
|
||
code:
|
||
type: string
|
||
description: The 6-digit TOTP code
|
||
responses:
|
||
'200':
|
||
description: Login successful
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
token:
|
||
type: string
|
||
description: Bearer authentication token (for users/employees)
|
||
session:
|
||
type: string
|
||
description: Session token (for subusers)
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/auth/reCAPTCHA/public:
|
||
get:
|
||
tags:
|
||
- Authentication
|
||
summary: Get reCAPTCHA configuration
|
||
description: Retrieve public reCAPTCHA configuration for login forms
|
||
operationId: getRecaptchaConfig
|
||
security: []
|
||
responses:
|
||
'200':
|
||
description: reCAPTCHA configuration retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
rate_limit:
|
||
type: object
|
||
properties:
|
||
enabled:
|
||
type: boolean
|
||
limit:
|
||
type: integer
|
||
remaining:
|
||
type: integer
|
||
reset:
|
||
type: integer
|
||
warning:
|
||
type: string
|
||
nullable: true
|
||
recaptcha:
|
||
type: object
|
||
|
||
/auth/register/cvr:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Register new customer by CVR
|
||
description: Register a new customer account using Danish CVR number
|
||
operationId: registerCustomerByCvr
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- cvr
|
||
- companyPhone
|
||
- invoiceEmail
|
||
- contactEmail
|
||
- contactPhone
|
||
- contactName
|
||
properties:
|
||
cvr:
|
||
type: string
|
||
description: Danish CVR number
|
||
minLength: 8
|
||
maxLength: 20
|
||
example: "44794780"
|
||
companyPhone:
|
||
type: integer
|
||
description: Company phone number
|
||
minimum: 10000000
|
||
maximum: 9999999999
|
||
example: 21754690
|
||
invoiceEmail:
|
||
type: string
|
||
format: email
|
||
description: Email for invoices
|
||
minLength: 5
|
||
maxLength: 255
|
||
example: "invoice@company.dk"
|
||
contactEmail:
|
||
type: string
|
||
format: email
|
||
description: Contact email
|
||
minLength: 5
|
||
maxLength: 255
|
||
example: "contact@company.dk"
|
||
contactPhone:
|
||
type: integer
|
||
description: Contact phone number
|
||
minimum: 10000000
|
||
maximum: 9999999999
|
||
example: 21754690
|
||
contactName:
|
||
type: string
|
||
description: Contact person name
|
||
example: "Mikkel"
|
||
responses:
|
||
'201':
|
||
description: Customer registered successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/auth/password-reset/request:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Request a customer password reset email
|
||
description: Send an email with a password reset token to the customer's email address
|
||
operationId: requestPasswordReset
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- customer_number
|
||
properties:
|
||
customer_number:
|
||
type: integer
|
||
description: The customer number
|
||
example: 123456
|
||
responses:
|
||
'200':
|
||
description: Request processed
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/auth/password-reset/validate:
|
||
get:
|
||
tags:
|
||
- Authentication
|
||
summary: Validate a customer password reset key
|
||
description: Check if a password reset token is valid and hasn't expired
|
||
operationId: validatePasswordResetToken
|
||
security: []
|
||
parameters:
|
||
- name: token
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: The password reset token
|
||
responses:
|
||
'200':
|
||
description: Token is valid
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
valid:
|
||
type: boolean
|
||
customer_id:
|
||
type: integer
|
||
'404':
|
||
description: Invalid or expired token
|
||
|
||
/auth/password-reset/set:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Set a customer password using a reset key
|
||
description: Update the customer password using a valid reset token
|
||
operationId: setPasswordUsingResetToken
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- token
|
||
- password
|
||
properties:
|
||
token:
|
||
type: string
|
||
description: The password reset token
|
||
password:
|
||
type: string
|
||
description: The new password
|
||
responses:
|
||
'200':
|
||
description: Password updated successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
description: Invalid or expired token
|
||
|
||
/su/intimidate:
|
||
post:
|
||
tags:
|
||
- Authentication
|
||
summary: Intimidate a user
|
||
description: Create an authentication token for another user (Superuser only)
|
||
operationId: suIntimidate
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [user_id]
|
||
properties:
|
||
user_id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
token: {type: string}
|
||
|
||
# User Endpoints
|
||
/users:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: List users
|
||
description: Retrieve a paginated list of users
|
||
operationId: listUsers
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
responses:
|
||
'200':
|
||
description: Users retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/User'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Create new user
|
||
description: Create a new user account
|
||
operationId: createUser
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/UserCreate'
|
||
responses:
|
||
'201':
|
||
description: User created successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
put:
|
||
tags:
|
||
- Users
|
||
summary: Update user
|
||
description: Update an existing user
|
||
operationId: updateUser
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/UserUpdate'
|
||
responses:
|
||
'200':
|
||
description: User updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/users/customer:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer details
|
||
description: Get details about a specific customer
|
||
operationId: getCustomer
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Customer retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/superuser/user:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get user by ID (superuser)
|
||
description: Get detailed user information by user ID
|
||
operationId: getSuperuserUser
|
||
parameters:
|
||
- name: user_id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: User retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/admin/customer/code:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer code
|
||
operationId: getCustomerCode
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
schema: {type: integer}
|
||
- name: user_id
|
||
in: query
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Add customer code
|
||
operationId: addCustomerCode
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
customer_number: {type: integer}
|
||
user_id: {type: integer}
|
||
code: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/customer/department/default:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer default department
|
||
operationId: getCustomerDefaultDepartment
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Add customer default department
|
||
operationId: addCustomerDefaultDepartment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [department]
|
||
properties:
|
||
customer_number: {type: integer}
|
||
department: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
delete:
|
||
tags:
|
||
- Users
|
||
summary: Delete customer default department
|
||
operationId: deleteCustomerDefaultDepartment
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/customer/pricing/fixed:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer fixed pricing
|
||
operationId: getCustomerFixedPricing
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Add customer fixed pricing
|
||
operationId: addCustomerFixedPricing
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [customer_number, price, description]
|
||
properties:
|
||
customer_number: {type: integer}
|
||
price: {type: integer}
|
||
description: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
delete:
|
||
tags:
|
||
- Users
|
||
summary: Delete customer fixed pricing
|
||
operationId: deleteCustomerFixedPricing
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/account/notifications:
|
||
put:
|
||
tags:
|
||
- Users
|
||
summary: Update user notification settings
|
||
operationId: updateUserNotifications
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
wash_certificate_email: {type: string}
|
||
sms_notifications_enabled: {type: boolean}
|
||
email_notifications_enabled: {type: boolean}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/user/permissions:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get user permissions
|
||
operationId: getUserPermissions
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/customers:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: List customers
|
||
operationId: listCustomers
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/user/discounts:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get user discounts
|
||
operationId: getUserDiscounts
|
||
parameters:
|
||
- name: user_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Set user discount
|
||
operationId: setUserDiscount
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [discount, object_id, is_category]
|
||
properties:
|
||
user_id: {type: integer}
|
||
discount: {type: integer}
|
||
object_id: {type: string}
|
||
is_category: {type: boolean}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/user/keys:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get user keys
|
||
operationId: getUserKeys
|
||
parameters:
|
||
- name: user_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
- name: key
|
||
in: query
|
||
schema: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Set user key
|
||
operationId: setUserKey
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [key, value]
|
||
properties:
|
||
user_id: {type: integer}
|
||
key: {type: string}
|
||
value: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/user/password:
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Set user password
|
||
operationId: setUserPassword
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [password]
|
||
properties:
|
||
user_id: {type: integer}
|
||
password: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/admin/customer/getUserId:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get user ID from customer number
|
||
description: Convert e-conomic customer number to internal user ID
|
||
operationId: getUserIdFromCustomerNumber
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: User ID retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
user_id:
|
||
type: integer
|
||
|
||
/admin/customer/name:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer name
|
||
description: Get the full name of a customer
|
||
operationId: getCustomerName
|
||
parameters:
|
||
- name: user_id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Customer name retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
|
||
# Orders Endpoints
|
||
/orders:
|
||
get:
|
||
tags:
|
||
- Orders
|
||
summary: List orders
|
||
description: Retrieve a paginated list of orders
|
||
operationId: listOrders
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- name: show_wash_subscription
|
||
in: query
|
||
schema:
|
||
type: string
|
||
enum: [true, false]
|
||
responses:
|
||
'200':
|
||
description: Orders retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Order'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
post:
|
||
tags:
|
||
- Orders
|
||
summary: Create new order
|
||
description: Create a new wash order
|
||
operationId: createOrder
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/OrderCreate'
|
||
responses:
|
||
'201':
|
||
description: Order created successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Order'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
delete:
|
||
tags:
|
||
- Orders
|
||
summary: Delete order
|
||
description: Delete an existing order
|
||
operationId: deleteOrder
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order deleted successfully
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
put:
|
||
tags:
|
||
- Orders
|
||
summary: Update order (alias)
|
||
description: Update an existing order
|
||
operationId: updateOrders
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/OrderUpdate'
|
||
responses:
|
||
'200':
|
||
description: Order updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/order:
|
||
get:
|
||
tags:
|
||
- Orders
|
||
summary: Get order details
|
||
description: Get detailed information about a specific order
|
||
operationId: getOrder
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Order'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
put:
|
||
tags:
|
||
- Orders
|
||
summary: Update order
|
||
description: Update an existing order
|
||
operationId: updateOrder
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/OrderUpdate'
|
||
responses:
|
||
'200':
|
||
description: Order updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
|
||
/user/orders:
|
||
get:
|
||
tags:
|
||
- Orders
|
||
summary: Get current user's orders
|
||
description: Retrieve orders for the authenticated user
|
||
operationId: getUserOrders
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Orders retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Order'
|
||
|
||
/user/order:
|
||
get:
|
||
tags:
|
||
- Orders
|
||
summary: Get user's specific order
|
||
description: Get details of a specific order for the authenticated user
|
||
operationId: getUserOrder
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Order'
|
||
|
||
/orders/mark_as_completed:
|
||
post:
|
||
tags:
|
||
- Orders
|
||
summary: Mark order as completed
|
||
description: Mark an order as completed
|
||
operationId: markOrderCompleted
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order marked as completed successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/order/wash-certificate:
|
||
post:
|
||
tags:
|
||
- Orders
|
||
summary: Generate wash certificate
|
||
description: Generate a wash certificate for an order
|
||
operationId: generateWashCertificate
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
order_id:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Wash certificate generated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
# Order Items Endpoints
|
||
/order/items:
|
||
get:
|
||
tags:
|
||
- Order Items
|
||
summary: List order items
|
||
description: Get all items for a specific order
|
||
operationId: listOrderItems
|
||
parameters:
|
||
- name: order_id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order items retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/OrderItem'
|
||
post:
|
||
tags:
|
||
- Order Items
|
||
summary: Add item to order
|
||
description: Add a new item to an existing order
|
||
operationId: addOrderItem
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/OrderItemCreate'
|
||
responses:
|
||
'201':
|
||
description: Order item added successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
put:
|
||
tags:
|
||
- Order Items
|
||
summary: Update order item
|
||
description: Update an existing order item
|
||
operationId: updateOrderItem
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/OrderItemUpdate'
|
||
responses:
|
||
'200':
|
||
description: Order item updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
delete:
|
||
tags:
|
||
- Order Items
|
||
summary: Delete order item
|
||
description: Remove an item from an order
|
||
operationId: deleteOrderItem
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order item deleted successfully
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
# Departments Endpoints
|
||
/departments:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: List departments
|
||
description: Retrieve a list of all visible departments
|
||
operationId: listDepartments
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
description: Filter by specific department ID
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
responses:
|
||
'200':
|
||
description: Departments retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Department'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
post:
|
||
tags:
|
||
- Departments
|
||
summary: Create department
|
||
description: Create a new department
|
||
operationId: createDepartment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentCreate'
|
||
responses:
|
||
'201':
|
||
description: Department created successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
put:
|
||
tags:
|
||
- Departments
|
||
summary: Update department
|
||
description: Update an existing department
|
||
operationId: updateDepartment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentUpdate'
|
||
responses:
|
||
'200':
|
||
description: Department updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/departments/categories:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get department categories
|
||
description: Get product categories available in a department
|
||
operationId: getDepartmentCategories
|
||
parameters:
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Department categories retrieved successfully
|
||
post:
|
||
tags:
|
||
- Departments
|
||
summary: Add category to department
|
||
description: Associate a product category with a department
|
||
operationId: addDepartmentCategory
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
department_id:
|
||
type: integer
|
||
category_id:
|
||
type: integer
|
||
responses:
|
||
'201':
|
||
description: Category added to department successfully
|
||
delete:
|
||
tags:
|
||
- Departments
|
||
summary: Remove category from department
|
||
operationId: removeDepartmentCategory
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/departments/self-serve/enabled:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get department self-serve status
|
||
description: Check if self-serve is enabled for a specific department
|
||
operationId: getDepartmentSelfServeEnabled
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Department ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved status
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
enabled:
|
||
type: boolean
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
put:
|
||
tags:
|
||
- Departments
|
||
summary: Update department self-serve status
|
||
description: Enable or disable self-serve for a specific department
|
||
operationId: updateDepartmentSelfServeEnabled
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Department ID
|
||
schema:
|
||
type: integer
|
||
- name: enabled
|
||
in: query
|
||
required: true
|
||
description: Enabled status (true/false)
|
||
schema:
|
||
type: string
|
||
enum: ['true', 'false']
|
||
responses:
|
||
'200':
|
||
description: Status updated successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/departments/order/recommended:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get recommended order for department
|
||
operationId: getDepartmentRecommendedOrder
|
||
parameters:
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/department/lanes:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: List department lanes
|
||
description: Retrieve a list of all department lanes
|
||
operationId: listDepartmentLanes
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
responses:
|
||
'200':
|
||
description: Department lanes retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentLane'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
post:
|
||
tags:
|
||
- Departments
|
||
summary: Create department lane
|
||
description: Create a new department lane
|
||
operationId: createDepartmentLane
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentLaneCreate'
|
||
responses:
|
||
'201':
|
||
description: Department lane created successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
put:
|
||
tags:
|
||
- Departments
|
||
summary: Update department lane
|
||
description: Update an existing department lane
|
||
operationId: updateDepartmentLane
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentLaneUpdate'
|
||
responses:
|
||
'200':
|
||
description: Department lane updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/lanes/dynamic-image:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Generate dynamic image for a department lane
|
||
description: |
|
||
Returns a composed machine UI image for the specified department lane.
|
||
You can optionally highlight button indices, set the current step indicator, and toggle only-current-step mode.
|
||
operationId: getDepartmentLaneDynamicImage
|
||
parameters:
|
||
- name: department
|
||
in: query
|
||
required: true
|
||
description: Department ID
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
- name: lane
|
||
in: query
|
||
required: true
|
||
description: Lane ID
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
- name: buttons
|
||
in: query
|
||
required: false
|
||
description: Highlighted button IDs (0-indexed). Accepts CSV, JSON array, or repeated query params.
|
||
schema:
|
||
oneOf:
|
||
- type: string
|
||
- type: array
|
||
items:
|
||
type: integer
|
||
- name: current_step
|
||
in: query
|
||
required: false
|
||
description: Current step indicator (non-negative integer)
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
- name: only_current_step
|
||
in: query
|
||
required: false
|
||
description: If true, only draw the current step highlight
|
||
schema:
|
||
type: boolean
|
||
- name: vehicle_type
|
||
in: query
|
||
required: false
|
||
description: Vehicle type selection override (nullable non-negative integer)
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
responses:
|
||
'200':
|
||
description: Dynamic image rendered successfully
|
||
content:
|
||
image/png:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/guest/validation/customer-number:
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Validate customer number
|
||
description: Check if a customer number is valid and exists
|
||
operationId: validateCustomerNumber
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- customer_number
|
||
properties:
|
||
customer_number:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Customer number validation successful
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/guest/departments:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: List public departments
|
||
description: Get list of departments without authentication
|
||
operationId: listGuestDepartments
|
||
security: []
|
||
responses:
|
||
'200':
|
||
description: Departments retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Department'
|
||
|
||
/department/selfserve/questions:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: List self-serve questions
|
||
description: Retrieve a list of self-serve questions for a department, lane, or product.
|
||
operationId: listSelfserveQuestions
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
description: Filter by question ID
|
||
schema:
|
||
type: integer
|
||
- name: department
|
||
in: query
|
||
description: Filter by department ID
|
||
schema:
|
||
type: integer
|
||
- name: lane
|
||
in: query
|
||
description: Filter by lane ID
|
||
schema:
|
||
type: integer
|
||
- name: product
|
||
in: query
|
||
description: Filter by product ID
|
||
schema:
|
||
type: integer
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved questions
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentSelfserveQuestion'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
post:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Add self-serve question
|
||
description: Add a new self-serve question.
|
||
operationId: addSelfserveQuestion
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- department
|
||
- lane
|
||
- product
|
||
- question
|
||
- description
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
product:
|
||
type: integer
|
||
question:
|
||
type: string
|
||
description:
|
||
type: string
|
||
condition_id:
|
||
type: integer
|
||
nullable: true
|
||
order_priority:
|
||
type: integer
|
||
default: 0
|
||
responses:
|
||
'200':
|
||
description: Successfully added question
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveQuestion'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
put:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Update self-serve question
|
||
description: Update an existing self-serve question.
|
||
operationId: updateSelfserveQuestion
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Question ID
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
product:
|
||
type: integer
|
||
question:
|
||
type: string
|
||
description:
|
||
type: string
|
||
condition_id:
|
||
type: integer
|
||
nullable: true
|
||
order_priority:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully updated question
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveQuestion'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
delete:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Delete self-serve question
|
||
description: Delete a self-serve question by ID.
|
||
operationId: deleteSelfserveQuestion
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Question ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully deleted question
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
example: Question deleted
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/selfserve/conditions:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: List self-serve conditions
|
||
description: Retrieve a list of self-serve conditions for a department, lane, or product.
|
||
operationId: listSelfserveConditions
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
description: Filter by condition ID
|
||
schema:
|
||
type: integer
|
||
- name: department
|
||
in: query
|
||
description: Filter by department ID
|
||
schema:
|
||
type: integer
|
||
- name: lane
|
||
in: query
|
||
description: Filter by lane ID
|
||
schema:
|
||
type: integer
|
||
- name: product
|
||
in: query
|
||
description: Filter by product ID
|
||
schema:
|
||
type: integer
|
||
- name: condition_id
|
||
in: query
|
||
description: Filter by condition ID
|
||
schema:
|
||
type: integer
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved conditions
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentSelfserveCondition'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
post:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Add self-serve condition
|
||
description: Add a new self-serve condition.
|
||
operationId: addSelfserveCondition
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- department
|
||
- lane
|
||
- product
|
||
- name
|
||
- description
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
product:
|
||
type: integer
|
||
condition_id:
|
||
type: integer
|
||
nullable: true
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Successfully added condition
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveCondition'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
put:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Update self-serve condition
|
||
description: Update an existing self-serve condition.
|
||
operationId: updateSelfserveCondition
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Condition ID
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
product:
|
||
type: integer
|
||
condition_id:
|
||
type: integer
|
||
nullable: true
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Successfully updated condition
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveCondition'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
delete:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Delete self-serve condition
|
||
description: Delete a self-serve condition.
|
||
operationId: deleteSelfserveCondition
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Condition ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully deleted condition
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
example: Condition deleted
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/selfserve/condition/rules:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: List self-serve condition rules
|
||
description: Retrieve a list of self-serve condition rules.
|
||
operationId: listSelfserveConditionRules
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
description: Filter by rule ID
|
||
schema:
|
||
type: integer
|
||
- name: condition_id
|
||
in: query
|
||
description: Filter by condition ID
|
||
schema:
|
||
type: integer
|
||
- name: type
|
||
in: query
|
||
description: Filter by rule type
|
||
schema:
|
||
type: string
|
||
- name: object_type
|
||
in: query
|
||
description: Filter by object type
|
||
schema:
|
||
type: string
|
||
- name: object_id
|
||
in: query
|
||
description: Filter by object ID
|
||
schema:
|
||
type: integer
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved condition rules
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentSelfserveConditionRule'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
post:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Add self-serve condition rule
|
||
description: Add a new self-serve condition rule.
|
||
operationId: addSelfserveConditionRule
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- condition_id
|
||
- type
|
||
- object_type
|
||
- object_id
|
||
- name
|
||
- description
|
||
properties:
|
||
condition_id:
|
||
type: integer
|
||
type:
|
||
type: string
|
||
object_type:
|
||
type: string
|
||
object_id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Successfully added condition rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveConditionRule'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
put:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Update self-serve condition rule
|
||
description: Update an existing self-serve condition rule.
|
||
operationId: updateSelfserveConditionRule
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Rule ID
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
condition_id:
|
||
type: integer
|
||
type:
|
||
type: string
|
||
object_type:
|
||
type: string
|
||
object_id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Successfully updated condition rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveConditionRule'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
delete:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Delete self-serve condition rule
|
||
description: Delete a self-serve condition rule.
|
||
operationId: deleteSelfserveConditionRule
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Rule ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully deleted condition rule
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
example: Rule deleted
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/selfserve/vehicle/conditions:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: List vehicle conditions
|
||
description: Retrieve a list of vehicle conditions for a department, lane, reg, or question. Customers will only see their own vehicle conditions.
|
||
operationId: listSelfserveVehicleConditions
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
description: Filter by condition ID
|
||
schema:
|
||
type: integer
|
||
- name: department
|
||
in: query
|
||
description: Filter by department ID
|
||
schema:
|
||
type: integer
|
||
- name: lane
|
||
in: query
|
||
description: Filter by lane ID
|
||
schema:
|
||
type: integer
|
||
- name: reg
|
||
in: query
|
||
description: Filter by vehicle registration number
|
||
schema:
|
||
type: string
|
||
- name: question
|
||
in: query
|
||
description: Filter by question ID
|
||
schema:
|
||
type: integer
|
||
- name: customer_id
|
||
in: query
|
||
description: Filter by customer ID
|
||
schema:
|
||
type: integer
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved vehicle conditions
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentSelfserveVehicleCondition'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
post:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Add vehicle condition
|
||
description: Add a new vehicle condition (answer to a question). Customers can only add conditions for their own vehicles.
|
||
operationId: addSelfserveVehicleCondition
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- department
|
||
- lane
|
||
- reg
|
||
- question
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
reg:
|
||
type: string
|
||
question:
|
||
type: integer
|
||
value:
|
||
type: boolean
|
||
customer_id:
|
||
type: integer
|
||
nullable: true
|
||
responses:
|
||
'200':
|
||
description: Successfully added vehicle condition
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveVehicleCondition'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
put:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Update vehicle condition
|
||
description: Update an existing vehicle condition. Customers can only update conditions for their own vehicles.
|
||
operationId: updateSelfserveVehicleCondition
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Condition ID
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
reg:
|
||
type: string
|
||
question:
|
||
type: integer
|
||
value:
|
||
type: boolean
|
||
customer_id:
|
||
type: integer
|
||
nullable: true
|
||
responses:
|
||
'200':
|
||
description: Successfully updated vehicle condition
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveVehicleCondition'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
delete:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Delete vehicle condition
|
||
description: Delete a vehicle condition. Customers can only delete conditions for their own vehicles.
|
||
operationId: deleteSelfserveVehicleCondition
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Condition ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully deleted vehicle condition
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
example: Condition deleted
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/selfserve/tasks:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: List self-serve tasks
|
||
description: Retrieve a list of self-serve tasks for a department, lane, product, or condition_id.
|
||
operationId: listSelfserveTasks
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
description: Filter by task ID
|
||
schema:
|
||
type: integer
|
||
- name: department
|
||
in: query
|
||
description: Filter by department ID
|
||
schema:
|
||
type: integer
|
||
- name: lane
|
||
in: query
|
||
description: Filter by lane ID
|
||
schema:
|
||
type: integer
|
||
- name: product
|
||
in: query
|
||
description: Filter by product ID
|
||
schema:
|
||
type: integer
|
||
- name: condition_id
|
||
in: query
|
||
description: Filter by condition ID
|
||
schema:
|
||
type: integer
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved tasks
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentSelfserveTask'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
post:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Add self-serve task
|
||
description: Add a new self-serve task.
|
||
operationId: addSelfserveTask
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- department
|
||
- lane
|
||
- product
|
||
- task
|
||
- description
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
product:
|
||
type: integer
|
||
condition_id:
|
||
type: integer
|
||
nullable: true
|
||
task:
|
||
type: string
|
||
description:
|
||
type: string
|
||
order_priority:
|
||
type: integer
|
||
default: 0
|
||
services:
|
||
type: array
|
||
description: Optional services enabled by this task. Items must be valid service enum names.
|
||
items:
|
||
$ref: '#/components/schemas/SelfserveLaneService'
|
||
buttons:
|
||
type: array
|
||
description: Optional dynamic image button IDs enabled by this task.
|
||
items:
|
||
type: integer
|
||
default: []
|
||
dynamic_images_vehicle_type:
|
||
type: integer
|
||
nullable: true
|
||
description: Optional vehicle type selection override for the machine UI. Integer >= 0 or null.
|
||
responses:
|
||
'200':
|
||
description: Successfully added task
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveTask'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
put:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Update self-serve task
|
||
description: Update an existing self-serve task.
|
||
operationId: updateSelfserveTask
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Task ID
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
department:
|
||
type: integer
|
||
lane:
|
||
type: integer
|
||
product:
|
||
type: integer
|
||
condition_id:
|
||
type: integer
|
||
nullable: true
|
||
task:
|
||
type: string
|
||
description:
|
||
type: string
|
||
order_priority:
|
||
type: integer
|
||
services:
|
||
type: array
|
||
nullable: true
|
||
description: Services enabled by this task. Set to null to clear all services.
|
||
items:
|
||
$ref: '#/components/schemas/SelfserveLaneService'
|
||
buttons:
|
||
type: array
|
||
nullable: true
|
||
description: Button IDs enabled by this task. Set to null to clear all buttons.
|
||
items:
|
||
type: integer
|
||
dynamic_images_vehicle_type:
|
||
type: integer
|
||
nullable: true
|
||
description: Vehicle type selection override. Set to null to clear.
|
||
responses:
|
||
'200':
|
||
description: Successfully updated task
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentSelfserveTask'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
delete:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Delete self-serve task
|
||
description: Delete a self-serve task by ID.
|
||
operationId: deleteSelfserveTask
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Task ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully deleted task
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
example: Task deleted
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/selfserve/tasks/attachments:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: List task attachments
|
||
description: Retrieve a list of attachments for a specific self-serve task.
|
||
operationId: listSelfserveTaskAttachments
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
description: Task ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully retrieved task attachments
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
delete:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Delete task attachment
|
||
description: Remove an attachment from a specific self-serve task.
|
||
operationId: deleteSelfserveTaskAttachment
|
||
parameters:
|
||
- name: task_id
|
||
in: query
|
||
required: true
|
||
description: Task ID
|
||
schema:
|
||
type: integer
|
||
- name: attachment_id
|
||
in: query
|
||
required: true
|
||
description: Attachment ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Attachment deleted successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
message:
|
||
type: string
|
||
example: Attachment deleted successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/department/selfserve/tasks/attachments/upload:
|
||
post:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Upload task attachment
|
||
description: Upload a new attachment to a specific self-serve task using base64 encoding.
|
||
operationId: uploadSelfserveTaskAttachment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- task_id
|
||
- base64_file
|
||
- file_name
|
||
properties:
|
||
task_id:
|
||
type: integer
|
||
base64_file:
|
||
type: string
|
||
description: Base64 encoded file content
|
||
file_name:
|
||
type: string
|
||
description: Name of the file including extension
|
||
responses:
|
||
'200':
|
||
description: Attachment uploaded successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
/department/selfserve/tasks/attachments/download:
|
||
get:
|
||
tags:
|
||
- Self-Serve
|
||
summary: Download task attachment
|
||
description: Generate a download link for a specific self-serve task attachment.
|
||
operationId: downloadSelfserveTaskAttachment
|
||
parameters:
|
||
- name: task_id
|
||
in: query
|
||
required: true
|
||
description: Task ID
|
||
schema:
|
||
type: integer
|
||
- name: attachment_id
|
||
in: query
|
||
required: true
|
||
description: Attachment ID
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Successfully generated download link
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
download_link:
|
||
type: string
|
||
format: uri
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
# Products Endpoints
|
||
/products:
|
||
get:
|
||
tags:
|
||
- Products
|
||
summary: List products
|
||
description: Retrieve a list of products with optional filters for customer pricing and department
|
||
operationId: listProducts
|
||
parameters:
|
||
- name: customer_id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
description: Customer ID for custom pricing
|
||
- name: department_id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
description: Department ID for department-specific pricing
|
||
- name: category
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
description: Filter by category ID
|
||
- name: id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
description: Get specific product by ID
|
||
- name: final_price
|
||
in: query
|
||
schema:
|
||
type: boolean
|
||
description: Whether to return final prices including discounts
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Products retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Product'
|
||
post:
|
||
tags:
|
||
- Products
|
||
summary: Create product
|
||
description: Create a new product
|
||
operationId: createProduct
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ProductCreate'
|
||
responses:
|
||
'201':
|
||
description: Product created successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
put:
|
||
tags:
|
||
- Products
|
||
summary: Update product
|
||
description: Update an existing product
|
||
operationId: updateProduct
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ProductUpdate'
|
||
responses:
|
||
'200':
|
||
description: Product updated successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
# Categories Endpoints
|
||
/categories:
|
||
get:
|
||
tags:
|
||
- Categories
|
||
summary: List categories
|
||
description: Retrieve a list of product categories
|
||
operationId: listCategories
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Categories retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Category'
|
||
post:
|
||
tags:
|
||
- Categories
|
||
summary: Create category
|
||
description: Create a new product category
|
||
operationId: createCategory
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CategoryCreate'
|
||
responses:
|
||
'201':
|
||
description: Category created successfully
|
||
put:
|
||
tags:
|
||
- Categories
|
||
summary: Update category
|
||
description: Update an existing category
|
||
operationId: updateCategory
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CategoryUpdate'
|
||
responses:
|
||
'200':
|
||
description: Category updated successfully
|
||
|
||
# Bookings Endpoints
|
||
/bookings:
|
||
get:
|
||
tags:
|
||
- Bookings
|
||
summary: List bookings
|
||
description: Retrieve a list of bookings
|
||
operationId: listBookings
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Bookings retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Booking'
|
||
put:
|
||
tags:
|
||
- Bookings
|
||
summary: Update booking
|
||
description: Update an existing booking
|
||
operationId: updateBooking
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/BookingUpdate'
|
||
responses:
|
||
'200':
|
||
description: Booking updated successfully
|
||
|
||
/user/bookings:
|
||
get:
|
||
tags:
|
||
- Bookings
|
||
summary: Get user bookings
|
||
description: Retrieve bookings for the authenticated user
|
||
operationId: getUserBookings
|
||
responses:
|
||
'200':
|
||
description: User bookings retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Booking'
|
||
|
||
|
||
/order-bookings:
|
||
get:
|
||
tags:
|
||
- Bookings
|
||
summary: List order bookings
|
||
operationId: listOrderBookings
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: false
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
# Goals Endpoints
|
||
/goals/department:
|
||
get:
|
||
tags:
|
||
- Goals
|
||
summary: List or get department goals
|
||
description: |
|
||
Retrieve a list of department goals or a single goal when `id` is provided.
|
||
|
||
Access control:
|
||
- A user may only access goals where the goal's `departments` set is a subset of the user's departments.
|
||
- Users with the `superuser` permission may access all goals.
|
||
operationId: listDepartmentGoals
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: false
|
||
schema: { type: integer }
|
||
description: When provided, returns the single goal with this id (if accessible)
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Goals retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/DepartmentGoal'
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
post:
|
||
tags:
|
||
- Goals
|
||
summary: Create department goal
|
||
description: |
|
||
Create a new department goal.
|
||
|
||
Access control:
|
||
- The provided `departments` must be a subset of the user's departments unless the user has `superuser`.
|
||
operationId: createDepartmentGoal
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentGoalCreate'
|
||
responses:
|
||
'201':
|
||
description: Department goal created successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentGoal'
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
put:
|
||
tags:
|
||
- Goals
|
||
summary: Update department goal
|
||
description: |
|
||
Update an existing department goal by `id`.
|
||
|
||
Access control:
|
||
- The creator (`created_by`) may update regardless of department membership.
|
||
- Otherwise the user must satisfy the same subset rule as for read access, and any new `departments` provided must also be a subset unless the user has `superuser`.
|
||
operationId: updateDepartmentGoal
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentGoalUpdate'
|
||
responses:
|
||
'200':
|
||
description: Department goal updated successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/DepartmentGoal'
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/goals/department/progress-alert/test:
|
||
post:
|
||
tags:
|
||
- Goals
|
||
summary: Send a test progress alert for a department goal
|
||
description: |
|
||
Sends a progress alert for a department goal to the destination defined in the goal's criteria.
|
||
|
||
Permission required: `goals_department_progress_alert_test`.
|
||
|
||
Access control:
|
||
- The caller must be a superuser or belong to all departments targeted by the goal.
|
||
|
||
Behavior:
|
||
- Looks up the goal by `id`.
|
||
- Rebuilds the criteria from stored JSON and attaches the goal's departments.
|
||
- Renders the alert using the server-side renderer (respecting progress type/style/format and destination limits).
|
||
- Sends the alert to Slack, Email, or SMS depending on `progress_alert_destination`, unless overridden.
|
||
operationId: sendDepartmentGoalProgressAlertTest
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: The department goal id
|
||
example: 42
|
||
overrideDestination:
|
||
type: string
|
||
description: Override the destination for this test
|
||
enum: [SLACK, EMAIL, SMS, NONE]
|
||
example: SLACK
|
||
email_to:
|
||
type: string
|
||
format: email
|
||
description: Email recipient when destination is EMAIL
|
||
example: tester@example.com
|
||
subject:
|
||
type: string
|
||
description: Optional email subject when destination is EMAIL
|
||
example: Dept Goal Progress Test
|
||
sms_to:
|
||
description: One or more MSISDN recipients when destination is SMS
|
||
oneOf:
|
||
- type: string
|
||
description: Comma or semicolon separated list
|
||
example: "+4512345678, +4598765432"
|
||
- type: array
|
||
items:
|
||
type: string
|
||
example: ["+4512345678", "+4598765432"]
|
||
slack_webhook:
|
||
type: string
|
||
description: Slack webhook URL when destination is SLACK
|
||
example: https://hooks.slack.com/services/T000/B000/XXX
|
||
department_id:
|
||
type: integer
|
||
description: Department id to use that department's Slack webhook when destination is SLACK
|
||
example: 3
|
||
responses:
|
||
'200':
|
||
description: Alert sent successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Goal id
|
||
destination:
|
||
type: string
|
||
description: Final destination used
|
||
enum: [SLACK, EMAIL, SMS, NONE]
|
||
target:
|
||
description: The target used for delivery (email address, phone numbers, department id, or webhook)
|
||
message_preview:
|
||
type: string
|
||
description: Rendered message preview
|
||
provider_response:
|
||
description: Provider-specific response or status message
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'500': { $ref: '#/components/responses/InternalServerError' }
|
||
delete:
|
||
tags:
|
||
- Goals
|
||
summary: Delete department goal
|
||
description: |
|
||
Delete a department goal by `id`.
|
||
|
||
Access control:
|
||
- The creator (`created_by`) may delete regardless of department membership.
|
||
- Otherwise the user must satisfy the subset rule or have `superuser`.
|
||
operationId: deleteDepartmentGoal
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: { type: integer }
|
||
description: ID of the goal to delete
|
||
responses:
|
||
'200':
|
||
description: Department goal deleted successfully
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
'/order-bookings':
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Create order booking
|
||
operationId: createOrderBooking
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [department, reg_1, datetime, items]
|
||
properties:
|
||
customer_number: {type: integer}
|
||
department: {type: integer}
|
||
reg_1: {type: string}
|
||
reg_2: {type: string}
|
||
reg_3: {type: string}
|
||
datetime: {type: string, format: date-time}
|
||
note: {type: string}
|
||
reference: {type: string}
|
||
po: {type: string}
|
||
pickup: {type: boolean}
|
||
items:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required: [id, quantity]
|
||
properties:
|
||
id: {type: integer}
|
||
quantity: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
put:
|
||
tags:
|
||
- Bookings
|
||
summary: Update order booking
|
||
operationId: updateOrderBooking
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
customer_number: {type: integer}
|
||
department: {type: integer}
|
||
reg_1: {type: string}
|
||
reg_2: {type: string}
|
||
reg_3: {type: string}
|
||
datetime: {type: string, format: date-time}
|
||
note: {type: string}
|
||
reference: {type: string}
|
||
po: {type: string}
|
||
pickup: {type: boolean}
|
||
order_id: {type: integer}
|
||
items:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required: [id, quantity]
|
||
properties:
|
||
id: {type: integer}
|
||
quantity: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
delete:
|
||
tags:
|
||
- Bookings
|
||
summary: Delete order booking
|
||
operationId: deleteOrderBooking
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/order-bookings/complete:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Complete order booking
|
||
operationId: completeOrderBooking
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
safety_seal: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/admin/bookings/sync:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Sync booking from external system
|
||
operationId: syncBooking
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/admin/bookings/department/count:
|
||
get:
|
||
tags:
|
||
- Bookings
|
||
summary: Get department unfulfilled bookings count
|
||
operationId: getDepartmentBookingCount
|
||
parameters:
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/user/bookings/washcertificate/download:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Get download link for own wash certificate
|
||
operationId: downloadOwnWashCertificate
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/bookings/download_pdf:
|
||
get:
|
||
tags:
|
||
- Bookings
|
||
summary: Download booking PDF
|
||
operationId: downloadBookingPdf
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/admin/bookings/delete:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Delete booking (admin)
|
||
operationId: adminDeleteBooking
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/bookings/sync/all:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Sync all bookings from external system
|
||
operationId: syncAllBookings
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/admin/bookings/completeWashWithoutWashCertificate:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Complete wash without wash certificate
|
||
operationId: completeWashWithoutWashCertificate
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/user/bookings/delete:
|
||
post:
|
||
tags:
|
||
- Bookings
|
||
summary: Delete own booking
|
||
operationId: deleteOwnBooking
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
# Invoices Endpoints
|
||
/invoices/draft:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: List draft invoices
|
||
description: Retrieve a list of draft invoices
|
||
operationId: listDraftInvoices
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Draft invoices retrieved successfully
|
||
|
||
/invoices/draft/close:
|
||
post:
|
||
tags:
|
||
- Invoices
|
||
summary: Close draft invoice
|
||
description: Close a draft invoice
|
||
operationId: closeDraftInvoice
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Draft invoice closed successfully
|
||
|
||
/invoices/pdf:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Get invoice PDF
|
||
description: Download an invoice as PDF
|
||
operationId: getInvoicePdf
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: PDF retrieved successfully
|
||
content:
|
||
application/pdf:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
|
||
/user/invoices:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Get user invoices
|
||
description: Retrieve invoices for the authenticated user
|
||
operationId: getUserInvoices
|
||
responses:
|
||
'200':
|
||
description: User invoices retrieved successfully
|
||
|
||
/collected-invoices:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: List collected invoices
|
||
description: Get list of collected invoices
|
||
operationId: listCollectedInvoices
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Collected invoices retrieved successfully
|
||
post:
|
||
tags:
|
||
- Invoices
|
||
summary: Create collected invoice
|
||
description: Create a new collected invoice
|
||
operationId: createCollectedInvoice
|
||
responses:
|
||
'201':
|
||
description: Collected invoice created successfully
|
||
put:
|
||
tags:
|
||
- Invoices
|
||
summary: Update collected invoice
|
||
description: Update a collected invoice
|
||
operationId: updateCollectedInvoice
|
||
responses:
|
||
'200':
|
||
description: Collected invoice updated successfully
|
||
|
||
/collected-invoices/ready-to-invoice:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Get invoices ready to process
|
||
description: Get collected invoices that are ready to be processed
|
||
operationId: getReadyToInvoice
|
||
responses:
|
||
'200':
|
||
description: Ready invoices retrieved successfully
|
||
|
||
/collected-invoices/economic/compare:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Compare collected invoice totals with E-conomic
|
||
description: |
|
||
Compares a collected invoice in the system with its corresponding invoice in E-conomic.
|
||
Returns totals from both sources, their difference, and any warnings detected during comparison.
|
||
operationId: compareCollectedInvoiceEconomic
|
||
parameters:
|
||
- name: collected_invoice_id
|
||
in: query
|
||
required: true
|
||
description: The internal collected invoice ID to compare
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
responses:
|
||
'200':
|
||
description: Comparison completed successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/CollectedInvoiceEconomicCompareResponse'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
/superuser/invoicing/period:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Get invoicing periods
|
||
description: Retrieve invoicing periods for superusers
|
||
operationId: getInvoicingPeriods
|
||
parameters:
|
||
- name: dateFrom
|
||
in: query
|
||
required: true
|
||
schema: {type: string, format: date}
|
||
- name: dateTo
|
||
in: query
|
||
required: true
|
||
schema: {type: string, format: date}
|
||
responses:
|
||
'200':
|
||
description: Invoicing periods retrieved successfully
|
||
|
||
/superuser/invoicing/period/distribution/fixed-pricing:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Get fixed pricing distribution
|
||
description: Get invoicing distribution for fixed pricing items
|
||
operationId: getInvoicingFixedPricingDistribution
|
||
parameters:
|
||
- name: dateFrom
|
||
in: query
|
||
required: true
|
||
schema: {type: string, format: date}
|
||
- name: dateTo
|
||
in: query
|
||
required: true
|
||
schema: {type: string, format: date}
|
||
responses:
|
||
'200':
|
||
description: Fixed pricing distribution retrieved successfully
|
||
|
||
/superuser/invoicing/period/distribution/wash-subscriptions:
|
||
get:
|
||
tags:
|
||
- Invoices
|
||
summary: Get wash subscriptions distribution
|
||
description: Get invoicing distribution for wash subscriptions
|
||
operationId: getInvoicingWashSubscriptionsDistribution
|
||
parameters:
|
||
- name: dateFrom
|
||
in: query
|
||
required: true
|
||
schema: {type: string, format: date}
|
||
- name: dateTo
|
||
in: query
|
||
required: true
|
||
schema: {type: string, format: date}
|
||
responses:
|
||
'200':
|
||
description: Wash subscriptions distribution retrieved successfully
|
||
|
||
# Vehicles Endpoints
|
||
/vehicles:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: List vehicles
|
||
description: |
|
||
List vehicles or fetch a specific vehicle when `id` is provided.
|
||
|
||
- When `id` is present, returns a single vehicle object (404 if not found).
|
||
- Otherwise returns a paginated list of vehicles.
|
||
|
||
Permissions:
|
||
- Own scope: `list_own_vehicles` (linked to subuser node `VEHICLES_LIST`).
|
||
- Broader scope: `list_vehicles_other`.
|
||
|
||
Subusers may specify header `X-Customer-Number` to target a specific customer. If the broader
|
||
permission is missing, the list will automatically be restricted to the effective customer context.
|
||
operationId: listVehicles
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
- name: id
|
||
in: query
|
||
schema: {type: integer}
|
||
- name: reg
|
||
in: query
|
||
schema: {type: string}
|
||
- name: customer_id
|
||
in: query
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Vehicle(s) retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- $ref: '#/components/schemas/Vehicle'
|
||
- type: array
|
||
items:
|
||
$ref: '#/components/schemas/Vehicle'
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
post:
|
||
tags:
|
||
- Vehicles
|
||
summary: Add vehicle
|
||
operationId: addVehicle
|
||
description: |
|
||
Create a new vehicle for a customer.
|
||
|
||
Permissions:
|
||
- Own scope: `add_vehicle` (linked to subuser node `VEHICLES_ADD`).
|
||
- Broader scope: `add_vehicle_other`.
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [reg, type, wash_subscription]
|
||
properties:
|
||
reg:
|
||
type: string
|
||
minLength: 2
|
||
maxLength: 12
|
||
description: Vehicle registration number
|
||
type:
|
||
type: integer
|
||
description: Product ID representing the vehicle wash type
|
||
wash_subscription:
|
||
type: boolean
|
||
reference:
|
||
type: string
|
||
maxLength: 255
|
||
nullable: true
|
||
customer_id:
|
||
type: integer
|
||
description: Optional explicit target customer. Defaults to the effective customer context.
|
||
responses:
|
||
'200': {description: Vehicle created}
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
put:
|
||
tags:
|
||
- Vehicles
|
||
summary: Edit vehicle
|
||
operationId: editVehicle
|
||
description: |
|
||
Update fields on an existing vehicle.
|
||
|
||
Permissions:
|
||
- Own scope: `edit_vehicle` (linked to subuser node `VEHICLES_EDIT`).
|
||
- Broader scope: `edit_vehicle_other`.
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
reg:
|
||
type: string
|
||
minLength: 2
|
||
maxLength: 12
|
||
type: {type: integer}
|
||
wash_subscription: {type: boolean}
|
||
reference:
|
||
type: string
|
||
maxLength: 255
|
||
nullable: true
|
||
responses:
|
||
'200': {description: Vehicle updated}
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags:
|
||
- Vehicles
|
||
summary: Delete vehicle
|
||
operationId: deleteVehicle
|
||
description: |
|
||
Delete an existing vehicle.
|
||
|
||
Permissions:
|
||
- Own scope: `delete_vehicle` (linked to subuser node `VEHICLES_DELETE`).
|
||
- Broader scope: `delete_vehicle_other`.
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200': {description: Vehicle deleted}
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/vehicles/addons/available:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: Get available vehicle addons
|
||
description: |
|
||
Get list of available addons for a vehicle.
|
||
|
||
Permissions:
|
||
- Own scope: `list_vehicle_addon_own` (linked to subuser node `VEHICLES_LIST`).
|
||
- Broader scope: `list_vehicles_addon_other`.
|
||
operationId: getAvailableVehicleAddons
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Available addons retrieved successfully
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/vehicles/addons/toggle:
|
||
post:
|
||
tags:
|
||
- Vehicles
|
||
summary: Toggle vehicle addon
|
||
description: |
|
||
Enable or disable a vehicle addon for a vehicle.
|
||
|
||
Permissions:
|
||
- Own scope: `toggle_vehicle_addon_own` (linked to subuser node `VEHICLES_EDIT`).
|
||
- Broader scope: `toggle_vehicle_addon_other`.
|
||
operationId: toggleVehicleAddon
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [vehicle_id, addon_id]
|
||
properties:
|
||
vehicle_id:
|
||
type: integer
|
||
addon_id:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Vehicle addon toggled successfully
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/department/vehicles/unknown-customer:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: Get unknown customer vehicles in department
|
||
operationId: getUnknownCustomerVehicles
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/department/vehicle/customer-suggestions:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: Get vehicle customer suggestions
|
||
operationId: getVehicleCustomerSuggestions
|
||
parameters:
|
||
- name: reg
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/vehicles/set-auto-start-on-lpr:
|
||
post:
|
||
tags:
|
||
- Vehicles
|
||
summary: Set auto start on LPR
|
||
operationId: setVehicleAutoStartOnLpr
|
||
description: |
|
||
Enable or disable automatic start on LPR for a vehicle in XL Vask.
|
||
|
||
Permissions:
|
||
- Own scope: `set_auto_start_on_lpr` (linked to subuser node `VEHICLES_EDIT`).
|
||
- Broader scope: `set_auto_start_on_lpr_other`.
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, active]
|
||
properties:
|
||
id: {type: integer}
|
||
active: {type: boolean}
|
||
responses:
|
||
'200': {description: Success}
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/vehicles/set-vehicle-type-id:
|
||
post:
|
||
tags:
|
||
- Vehicles
|
||
summary: Set vehicle type ID
|
||
operationId: setVehicleTypeId
|
||
description: |
|
||
Set or change the XL Vask `vehicleTypeId` for a vehicle.
|
||
|
||
Permissions:
|
||
- Own scope: `set_vehicle_type_id` (linked to subuser node `VEHICLES_EDIT`).
|
||
- Broader scope: `set_vehicle_type_id_other`.
|
||
parameters:
|
||
- $ref: '#/components/parameters/XCustomerNumber'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, vehicleTypeId]
|
||
properties:
|
||
id: {type: integer}
|
||
vehicleTypeId:
|
||
type: string
|
||
minLength: 1
|
||
maxLength: 50
|
||
responses:
|
||
'200': {description: Success}
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/superuser/users-with-vehicle-subscriptions:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: Get users with vehicle subscriptions
|
||
operationId: getUsersWithVehicleSubscriptions
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/vehicles/status:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: Get vehicle status
|
||
operationId: getVehicleStatus
|
||
parameters:
|
||
- name: reg
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/vehicles/search:
|
||
get:
|
||
tags:
|
||
- Vehicles
|
||
summary: Search vehicles
|
||
operationId: searchVehicles
|
||
parameters:
|
||
- name: search
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
# Notifications Endpoints
|
||
/notifications:
|
||
get:
|
||
tags:
|
||
- Notifications
|
||
summary: List notifications
|
||
description: Get list of notifications
|
||
operationId: listNotifications
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Notifications retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Notification'
|
||
post:
|
||
tags:
|
||
- Notifications
|
||
summary: Create notification
|
||
description: Create a new notification
|
||
operationId: createNotification
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/NotificationCreate'
|
||
responses:
|
||
'201':
|
||
description: Notification created successfully
|
||
delete:
|
||
tags:
|
||
- Notifications
|
||
summary: Delete notification
|
||
description: Delete a notification
|
||
operationId: deleteNotification
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Notification deleted successfully
|
||
|
||
# Statistics Endpoints
|
||
/statistics/bookings/new:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get new bookings statistics
|
||
description: Get statistics for new bookings
|
||
operationId: getNewBookingsStats
|
||
responses:
|
||
'200':
|
||
description: New bookings statistics retrieved successfully
|
||
|
||
/orders/module/stripe/payment_intent:
|
||
get:
|
||
tags:
|
||
- Orders
|
||
summary: Get Stripe payment intent
|
||
operationId: getStripePaymentIntent
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Orders
|
||
summary: Create Stripe payment intent
|
||
operationId: createStripePaymentIntent
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, reader]
|
||
properties:
|
||
id: {type: integer}
|
||
reader: {type: string}
|
||
tax_percentage: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
delete:
|
||
tags:
|
||
- Orders
|
||
summary: Delete Stripe payment intent
|
||
operationId: deleteStripePaymentIntent
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/orders/module/stripe/payment_intent/capture:
|
||
post:
|
||
tags:
|
||
- Orders
|
||
summary: Capture Stripe payment intent
|
||
operationId: captureStripePaymentIntent
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/orders/module/stripe/debug/simulate_payment:
|
||
post:
|
||
tags:
|
||
- Orders
|
||
summary: Simulate Stripe payment
|
||
operationId: simulateStripePayment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/statistics/orders/new:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get new orders statistics
|
||
description: Get statistics for new orders
|
||
operationId: getNewOrdersStats
|
||
responses:
|
||
'200':
|
||
description: New orders statistics retrieved successfully
|
||
|
||
/statistics/income/today:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get today's income
|
||
description: Get income statistics for today
|
||
operationId: getTodayIncome
|
||
responses:
|
||
'200':
|
||
description: Today's income statistics retrieved successfully
|
||
|
||
/statistics/income/yesterday:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get yesterday's income
|
||
description: Get income statistics for yesterday
|
||
operationId: getYesterdayIncome
|
||
responses:
|
||
'200':
|
||
description: Yesterday's income statistics retrieved successfully
|
||
|
||
/statistics/income/this-month:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get this month's income
|
||
description: Get income statistics for the current month
|
||
operationId: getThisMonthIncome
|
||
responses:
|
||
'200':
|
||
description: This month's income statistics retrieved successfully
|
||
|
||
/statistics/income/last-month:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get last month's income
|
||
description: Get income statistics for the previous month
|
||
operationId: getLastMonthIncome
|
||
responses:
|
||
'200':
|
||
description: Last month's income statistics retrieved successfully
|
||
|
||
/statistics/income/this-year:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get this year's income
|
||
description: Get income statistics for the current year
|
||
operationId: getThisYearIncome
|
||
responses:
|
||
'200':
|
||
description: This year's income statistics retrieved successfully
|
||
|
||
/statistics/income/departments:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get total income today by departments
|
||
operationId: getTotalIncomeTodayByDepartments
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/statistics/economic/totals:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get total economic statistics
|
||
operationId: getEconomicTotals
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/statistics/economic/totals/department_sent_invoice_totals:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get department sent invoice totals
|
||
operationId: getDepartmentSentInvoiceTotals
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/statistics/economic/totals/department_draft_invoice_totals:
|
||
get:
|
||
tags:
|
||
- Statistics
|
||
summary: Get department draft invoice totals
|
||
operationId: getDepartmentDraftInvoiceTotals
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
# Worker Endpoints
|
||
/worker/version:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Get worker version
|
||
description: Get the current version of the system worker
|
||
operationId: getWorkerVersion
|
||
responses:
|
||
'200':
|
||
description: Worker version retrieved successfully
|
||
|
||
/worker/update-version:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Update worker version
|
||
description: Set the target version for the worker update
|
||
operationId: updateWorkerVersion
|
||
parameters:
|
||
- name: version
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Version update target set successfully
|
||
|
||
/worker/status:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Get worker status
|
||
description: Get detailed status of the system worker
|
||
operationId: getWorkerStatus
|
||
responses:
|
||
'200':
|
||
description: Worker status retrieved successfully
|
||
|
||
/worker/debug:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Debug worker
|
||
description: Execute debug commands on the worker (often restricted)
|
||
operationId: debugWorker
|
||
responses:
|
||
'200':
|
||
description: Debug information retrieved successfully
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/worker/debug/on:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Enable worker debug
|
||
operationId: enableWorkerDebug
|
||
responses:
|
||
'200':
|
||
description: Worker debug enabled
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/worker/debug/off:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Disable worker debug
|
||
operationId: disableWorkerDebug
|
||
responses:
|
||
'200':
|
||
description: Worker debug disabled
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/worker/licenseplates:
|
||
get:
|
||
tags:
|
||
- Worker
|
||
summary: Get unique license plates
|
||
description: Fetch all unique license plates from various database tables
|
||
operationId: getWorkerLicensePlates
|
||
responses:
|
||
'200':
|
||
description: License plates retrieved successfully
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/economic/doesCustomerExist:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Check if customer exists in e-conomic
|
||
operationId: checkEconomicCustomerExists
|
||
parameters:
|
||
- name: cvr
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Customer check completed
|
||
'404':
|
||
$ref: '#/components/responses/NotFound'
|
||
|
||
/cvr/lookup:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Lookup CVR information
|
||
description: Get detailed information for a CVR number
|
||
operationId: lookupCvr
|
||
parameters:
|
||
- name: cvr
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: CVR information retrieved successfully
|
||
|
||
/cvr/search:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Search CVR
|
||
description: Search for companies by name or CVR
|
||
operationId: searchCvr
|
||
parameters:
|
||
- name: query
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
minLength: 2
|
||
responses:
|
||
'200':
|
||
description: Search results retrieved successfully
|
||
|
||
# Plate Scans Endpoints
|
||
/numberplatescans:
|
||
get:
|
||
tags:
|
||
- Plate Scans
|
||
summary: List plate scans
|
||
description: Get a list of license plate scans
|
||
operationId: listPlateScans
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
responses:
|
||
'200':
|
||
description: Plate scans retrieved successfully
|
||
post:
|
||
tags:
|
||
- Plate Scans
|
||
summary: Record plate scan
|
||
description: Record a new license plate scan
|
||
operationId: recordPlateScan
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- plate
|
||
- lane_id
|
||
properties:
|
||
plate:
|
||
type: string
|
||
lane_id:
|
||
type: integer
|
||
responses:
|
||
'201':
|
||
description: Plate scan recorded successfully
|
||
|
||
/numberplatescans/department:
|
||
post:
|
||
tags:
|
||
- Plate Scans
|
||
summary: Record plate scan for department
|
||
operationId: recordDepartmentPlateScan
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- plate
|
||
- department_id
|
||
properties:
|
||
plate:
|
||
type: string
|
||
department_id:
|
||
type: integer
|
||
responses:
|
||
'201':
|
||
description: Plate scan recorded successfully
|
||
|
||
/numberplatescans/post:
|
||
get:
|
||
tags:
|
||
- Plate Scans
|
||
summary: Get post-scan results
|
||
operationId: getPlateScanPostResults
|
||
responses:
|
||
'200':
|
||
description: Post-scan results retrieved successfully
|
||
|
||
/numberplatescanners:
|
||
get:
|
||
tags:
|
||
- Plate Scans
|
||
summary: List plate scanners
|
||
description: Get a list of all number plate scanners
|
||
operationId: listPlateScanners
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
responses:
|
||
'200':
|
||
description: Plate scanners retrieved successfully
|
||
post:
|
||
tags:
|
||
- Plate Scans
|
||
summary: Add plate scanner
|
||
operationId: addPlateScanner
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [department_id, name, notes]
|
||
properties:
|
||
department_id: {type: integer}
|
||
name: {type: string}
|
||
notes: {type: string}
|
||
responses:
|
||
'201':
|
||
description: Plate scanner added successfully
|
||
put:
|
||
tags:
|
||
- Plate Scans
|
||
summary: Update plate scanner
|
||
operationId: updatePlateScanner
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, department_id, name, notes]
|
||
properties:
|
||
id: {type: integer}
|
||
department_id: {type: integer}
|
||
name: {type: string}
|
||
notes: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Plate scanner updated successfully
|
||
|
||
/department/numberplatescanners:
|
||
get:
|
||
tags:
|
||
- Plate Scans
|
||
summary: List department plate scanners
|
||
operationId: listDepartmentPlateScanners
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Department plate scanners retrieved successfully
|
||
|
||
/relay/button/press/post:
|
||
get:
|
||
tags:
|
||
- Plate Scans
|
||
summary: Add button press
|
||
operationId: addButtonPress
|
||
parameters:
|
||
- name: token
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
responses:
|
||
'201':
|
||
description: Button press recorded
|
||
|
||
# Module - e-conomic Endpoints
|
||
/economic/customers/import:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Import e-conomic customers
|
||
description: Import customers from e-conomic
|
||
operationId: importEconomicCustomers
|
||
responses:
|
||
'200':
|
||
description: Customers imported successfully
|
||
|
||
/economic/departments:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get e-conomic departments
|
||
operationId: getEconomicDepartments
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/economic/products:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get e-conomic products
|
||
operationId: getEconomicProducts
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/economic/customer:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get e-conomic customer details
|
||
operationId: getEconomicCustomer
|
||
parameters:
|
||
- name: customer_number
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Create e-conomic customer
|
||
operationId: createEconomicCustomer
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [customer_number, cvr, email, phone, name]
|
||
properties:
|
||
customer_number: {type: integer}
|
||
cvr: {type: integer}
|
||
email: {type: string}
|
||
phone: {type: integer}
|
||
name: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/economic/layouts:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get e-conomic layouts
|
||
description: Get available invoice layouts from e-conomic
|
||
operationId: getEconomicLayouts
|
||
responses:
|
||
'200':
|
||
description: Layouts retrieved successfully
|
||
|
||
/economic/payment-terms:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get e-conomic payment terms
|
||
description: Get available payment terms from e-conomic
|
||
operationId: getEconomicPaymentTerms
|
||
responses:
|
||
'200':
|
||
description: Payment terms retrieved successfully
|
||
|
||
/economic/invoice/draft/export:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Export draft invoice to e-conomic
|
||
description: Export a draft invoice to e-conomic
|
||
operationId: exportDraftInvoiceToEconomic
|
||
responses:
|
||
'200':
|
||
description: Draft invoice exported successfully
|
||
|
||
/economic/invoice/export:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Export invoice to e-conomic
|
||
description: Export a booked invoice to e-conomic
|
||
operationId: exportInvoiceToEconomic
|
||
responses:
|
||
'200':
|
||
description: Invoice exported successfully
|
||
|
||
# Module - Stripe Endpoints
|
||
/modules/stripe/customers:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List Stripe customers
|
||
description: Get list of Stripe customers
|
||
operationId: listStripeCustomers
|
||
responses:
|
||
'200':
|
||
description: Stripe customers retrieved successfully
|
||
|
||
/modules/stripe/products:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List Stripe products
|
||
description: Get list of Stripe products
|
||
operationId: listStripeProducts
|
||
responses:
|
||
'200':
|
||
description: Stripe products retrieved successfully
|
||
|
||
/modules/stripe/prices:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List Stripe prices
|
||
description: Get list of Stripe prices
|
||
operationId: listStripePrices
|
||
responses:
|
||
'200':
|
||
description: Stripe prices retrieved successfully
|
||
|
||
/modules/stripe/invoice:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Create Stripe invoice
|
||
description: Create an invoice in Stripe
|
||
operationId: createStripeInvoice
|
||
responses:
|
||
'201':
|
||
description: Stripe invoice created successfully
|
||
|
||
/modules/stripe/terminal/readers:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List Stripe terminal readers
|
||
operationId: listStripeTerminalReaders
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/stripe/terminal/locations:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List Stripe terminal locations
|
||
operationId: listStripeTerminalLocations
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/stripe/department/terminal/location:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get department terminal location
|
||
operationId: getDepartmentTerminalLocation
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Set department terminal location
|
||
operationId: setDepartmentTerminalLocation
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, location]
|
||
properties:
|
||
id: {type: integer}
|
||
location: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/stripe/department/terminal/readers:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get department terminal readers
|
||
operationId: getDepartmentTerminalReaders
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
# Module - Backup Endpoints
|
||
/modules/backup/backups:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List backup modules
|
||
operationId: listBackupModules
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Create backup module
|
||
operationId: createBackupModule
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [name, description]
|
||
properties:
|
||
name: {type: string}
|
||
description: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
# Module - XLVask Endpoints
|
||
/modules/xlvask/usageLog:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get XLVask usage logs
|
||
description: Retrieve usage logs from XLVask system
|
||
operationId: getXlvaskUsageLogs
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Usage logs retrieved successfully
|
||
|
||
/modules/xlvask/vehicles:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List XLVask vehicles
|
||
description: Get list of vehicles from XLVask
|
||
operationId: listXlvaskVehicles
|
||
responses:
|
||
'200':
|
||
description: XLVask vehicles retrieved successfully
|
||
|
||
/modules/xlvask/customers:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List XLVask customers
|
||
description: Get list of customers from XLVask
|
||
operationId: listXlvaskCustomers
|
||
responses:
|
||
'200':
|
||
description: XLVask customers retrieved successfully
|
||
|
||
/modules/action-logs:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List module action logs
|
||
description: Retrieve a paginated list of module action logs with searching and filtering
|
||
operationId: listModuleActionLogs
|
||
parameters:
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/LimitParam'
|
||
- $ref: '#/components/parameters/SearchParam'
|
||
- $ref: '#/components/parameters/FiltersParam'
|
||
responses:
|
||
'200':
|
||
description: Module action logs retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/ModuleActionLog'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
# Module - Self-Serve Endpoints
|
||
/modules/self-serve/lane/status:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get self-serve lane status
|
||
description: Retrieve the current status of a self-serve lane
|
||
operationId: getSelfServeLaneStatus
|
||
parameters:
|
||
- name: lane_id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Lane status retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SelfServeLaneStatus'
|
||
|
||
/modules/self-serve/lane/command:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Send self-serve lane command
|
||
description: Send a command (e.g., start, stop, reset) to a self-serve lane
|
||
operationId: sendSelfServeLaneCommand
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane_id
|
||
- command
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
command:
|
||
type: string
|
||
enum: [START, STOP, RESET, RESERVE, RELEASE]
|
||
license_plate:
|
||
type: string
|
||
description: Required for START command
|
||
responses:
|
||
'200':
|
||
description: Command sent successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SelfServeLaneStatus'
|
||
|
||
/modules/self-serve/lane/services/allowed:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Set allowed services for a lane based on shown tasks
|
||
description: |
|
||
Updates the set of services that are allowed to be manually activated for a given self-serve lane,
|
||
derived from the tasks currently shown to the user after answering the self-serve questions.
|
||
This endpoint does not activate anything by itself; it only sets what is allowed to be activated.
|
||
operationId: setSelfServeLaneAllowedServices
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane_id
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
task_ids:
|
||
type: array
|
||
description: List of task IDs that are currently shown to the user
|
||
items:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Allowed services updated
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
allowed_services:
|
||
type: array
|
||
items:
|
||
type: string
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/modules/self-serve/lane/relay/machine/enable:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Manually enable MACHINE relay for a lane
|
||
description: |
|
||
Manually turns on the MACHINE relay for a self-serve lane if and only if the current allowed services
|
||
include `MACHINE` (set via `/modules/self-serve/lane/services/allowed`). The relay is never automatically
|
||
enabled; an explicit call to this endpoint is required.
|
||
operationId: enableSelfServeLaneMachineRelay
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane_id
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
duration:
|
||
type: integer
|
||
description: Optional number of seconds after which the relay should automatically turn off
|
||
responses:
|
||
'200':
|
||
description: MACHINE relay enabled
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
relay:
|
||
type: string
|
||
enabled:
|
||
type: boolean
|
||
duration:
|
||
type: integer
|
||
nullable: true
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
description: Not allowed to enable MACHINE relay (no matching task currently shown)
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Error'
|
||
|
||
/modules/self-serve/lane/force/machine/enable:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Force enable MACHINE relay and mark lane as in-wash (superusers only)
|
||
description: |
|
||
Superuser/emergency endpoint. Bypasses the allowed services gating and directly turns on the MACHINE relay.
|
||
Also ensures the lane is marked as OCCUPIED and IN_WASH with a wash start timestamp if not already set.
|
||
operationId: forceEnableSelfServeLaneMachine
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane_id
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
duration:
|
||
type: integer
|
||
nullable: true
|
||
description: Optional number of seconds after which the relay should automatically turn off
|
||
license_plate:
|
||
type: string
|
||
nullable: true
|
||
description: Optional license plate to associate with the lane
|
||
responses:
|
||
'200':
|
||
description: MACHINE relay force-enabled and lane marked in-wash
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
forced:
|
||
type: boolean
|
||
machine:
|
||
type: string
|
||
enum: [ENABLED]
|
||
duration:
|
||
type: integer
|
||
nullable: true
|
||
status:
|
||
type: string
|
||
state:
|
||
type: string
|
||
wash_start_time:
|
||
type: integer
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/modules/self-serve/lane/force/machine/disable:
|
||
post:
|
||
tags:
|
||
- Modules
|
||
summary: Force disable MACHINE relay but keep lane as in-wash (superusers only)
|
||
description: |
|
||
Superuser/emergency endpoint. Turns off the MACHINE relay while ensuring the lane remains in an IN_WASH state
|
||
(simulating a started wash without machine assistance).
|
||
operationId: forceDisableSelfServeLaneMachine
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required:
|
||
- lane_id
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
license_plate:
|
||
type: string
|
||
nullable: true
|
||
responses:
|
||
'200':
|
||
description: MACHINE relay force-disabled and lane ensured in-wash
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
lane_id:
|
||
type: integer
|
||
forced:
|
||
type: boolean
|
||
machine:
|
||
type: string
|
||
enum: [DISABLED]
|
||
status:
|
||
type: string
|
||
state:
|
||
type: string
|
||
wash_start_time:
|
||
type: integer
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
# Module - Other Integration Endpoints
|
||
/modules/motorapi/lookup:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Lookup vehicle via MotorAPI
|
||
description: Look up vehicle information using license plate
|
||
operationId: motorApiLookup
|
||
parameters:
|
||
- name: plate
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Vehicle information retrieved successfully
|
||
|
||
/modules/virkdata/search:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Search VirkData
|
||
description: Search for company information in VirkData
|
||
operationId: virkdataSearch
|
||
parameters:
|
||
- name: search
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Company information retrieved successfully
|
||
|
||
/modules/fxratesapi/rate:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get exchange rate
|
||
description: Get current exchange rate
|
||
operationId: getExchangeRate
|
||
parameters:
|
||
- name: from
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
- name: to
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Exchange rate retrieved successfully
|
||
|
||
/modules/fxratesapi/rates:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get all exchange rates
|
||
description: Get all available exchange rates
|
||
operationId: getAllExchangeRates
|
||
responses:
|
||
'200':
|
||
description: Exchange rates retrieved successfully
|
||
|
||
/modules/entra/users:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List Microsoft Entra users
|
||
description: Get list of users from Microsoft Entra (Azure AD)
|
||
operationId: listEntraUsers
|
||
responses:
|
||
'200':
|
||
description: Entra users retrieved successfully
|
||
|
||
# Attachments Endpoints
|
||
/attachments/upload:
|
||
post:
|
||
tags:
|
||
- Attachments
|
||
summary: Upload attachment
|
||
description: Upload a file attachment
|
||
operationId: uploadAttachment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
file:
|
||
type: string
|
||
format: binary
|
||
responses:
|
||
'201':
|
||
description: Attachment uploaded successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
|
||
/orders/attachments:
|
||
get:
|
||
tags:
|
||
- Attachments
|
||
summary: List order attachments
|
||
description: Get attachments for an order
|
||
operationId: listOrderAttachments
|
||
parameters:
|
||
- name: order_id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Order attachments retrieved successfully
|
||
|
||
/orders/attachments/upload:
|
||
post:
|
||
tags:
|
||
- Attachments
|
||
summary: Upload order attachment
|
||
description: Upload an attachment to an order
|
||
operationId: uploadOrderAttachment
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
order_id:
|
||
type: integer
|
||
file:
|
||
type: string
|
||
format: binary
|
||
responses:
|
||
'201':
|
||
description: Order attachment uploaded successfully
|
||
|
||
/orders/attachments/download:
|
||
get:
|
||
tags:
|
||
- Attachments
|
||
summary: Download order attachment
|
||
description: Download a specific order attachment
|
||
operationId: downloadOrderAttachment
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Attachment downloaded successfully
|
||
content:
|
||
application/octet-stream:
|
||
schema:
|
||
type: string
|
||
format: binary
|
||
|
||
# Forms Endpoints
|
||
/form:
|
||
get:
|
||
tags:
|
||
- Forms
|
||
summary: Get form
|
||
description: Retrieve a form definition
|
||
operationId: getForm
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Form retrieved successfully
|
||
post:
|
||
tags:
|
||
- Forms
|
||
summary: Submit form
|
||
description: Submit a form
|
||
operationId: submitForm
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
form_id:
|
||
type: integer
|
||
data:
|
||
type: object
|
||
responses:
|
||
'201':
|
||
description: Form submitted successfully
|
||
|
||
# Permissions Endpoints
|
||
/permissions:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: List permissions
|
||
description: Get list of all available permissions
|
||
operationId: listPermissions
|
||
responses:
|
||
'200':
|
||
description: Permissions retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Permission'
|
||
|
||
# Customer Management Endpoints
|
||
/customer/attributes:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer attributes
|
||
description: Get custom attributes for a customer
|
||
operationId: getCustomerAttributes
|
||
parameters:
|
||
- name: customer_id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Customer attributes retrieved successfully
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Add customer attribute
|
||
description: Add a custom attribute to a customer
|
||
operationId: addCustomerAttribute
|
||
responses:
|
||
'201':
|
||
description: Customer attribute added successfully
|
||
delete:
|
||
tags:
|
||
- Users
|
||
summary: Delete customer attribute
|
||
description: Remove a custom attribute from a customer
|
||
operationId: deleteCustomerAttribute
|
||
responses:
|
||
'200':
|
||
description: Customer attribute deleted successfully
|
||
|
||
/customer/notes:
|
||
get:
|
||
tags:
|
||
- Users
|
||
summary: Get customer notes
|
||
description: Get notes for a customer
|
||
operationId: getCustomerNotes
|
||
parameters:
|
||
- name: customer_id
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Customer notes retrieved successfully
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Add customer note
|
||
description: Add a note to a customer
|
||
operationId: addCustomerNote
|
||
responses:
|
||
'201':
|
||
description: Customer note added successfully
|
||
delete:
|
||
tags:
|
||
- Users
|
||
summary: Delete customer note
|
||
description: Remove a note from a customer
|
||
operationId: deleteCustomerNote
|
||
responses:
|
||
'200':
|
||
description: Customer note deleted successfully
|
||
|
||
/customers/search:
|
||
post:
|
||
tags:
|
||
- Users
|
||
summary: Search customers
|
||
description: Search for customers using various criteria
|
||
operationId: searchCustomers
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
query:
|
||
type: string
|
||
responses:
|
||
'200':
|
||
description: Customers found successfully
|
||
|
||
# Configuration Endpoints
|
||
/economic/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get e-conomic config
|
||
operationId: getEconomicConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update e-conomic config
|
||
operationId: updateEconomicConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/reCAPTCHA/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get reCAPTCHA config
|
||
operationId: getRecaptchaConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update reCAPTCHA config
|
||
operationId: updateRecaptchaConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/email/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get email config
|
||
operationId: getEmailConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update email config
|
||
operationId: updateEmailConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/email/config/test:
|
||
post:
|
||
tags: [Config]
|
||
summary: Test email config
|
||
operationId: testEmailConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/backups/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get backups config
|
||
operationId: getBackupsConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update backups config
|
||
operationId: updateBackupsConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/motorapi/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get MotorAPI config
|
||
operationId: getMotorApiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update MotorAPI config
|
||
operationId: updateMotorApiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/stripe/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get Stripe config
|
||
operationId: getStripeConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update Stripe config
|
||
operationId: updateStripeConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/fxratesapi/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get FXRatesAPI config
|
||
operationId: getFxRatesApiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update FXRatesAPI config
|
||
operationId: updateFxRatesApiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/gatewayapi/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get GatewayAPI config
|
||
operationId: getGatewayApiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update GatewayAPI config
|
||
operationId: updateGatewayApiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/xlvask/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get XLVask config
|
||
operationId: getXlvaskConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update XLVask config
|
||
operationId: updateXlvaskConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/entra/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get Entra config
|
||
operationId: getEntraConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update Entra config
|
||
operationId: updateEntraConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/limble/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get Limble config
|
||
operationId: getLimbleConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update Limble config
|
||
operationId: updateLimbleConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/ocrspace/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get OcrSpace config
|
||
operationId: getOcrSpaceConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update OcrSpace config
|
||
operationId: updateOcrSpaceConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/openai/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get OpenAI config
|
||
operationId: getOpenAiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update OpenAI config
|
||
operationId: updateOpenAiConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/licenseplaterecognizer/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get LicensePlateRecognizer config
|
||
operationId: getLicensePlateRecognizerConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update LicensePlateRecognizer config
|
||
operationId: updateLicensePlateRecognizerConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/virkdata/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get Virkdata config
|
||
operationId: getVirkdataConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update Virkdata config
|
||
operationId: updateVirkdataConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/shelly/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get Shelly config
|
||
operationId: getShellyConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
post:
|
||
tags: [Config]
|
||
summary: Update Shelly config
|
||
operationId: updateShellyConfig
|
||
responses:
|
||
'200': {description: Success}
|
||
|
||
/selfserve/config:
|
||
get:
|
||
tags: [Config]
|
||
summary: Get Self-Serve config
|
||
operationId: getSelfServeConfig
|
||
responses:
|
||
'200':
|
||
description: Self-serve configuration retrieved successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SelfServeConfig'
|
||
post:
|
||
tags: [Config]
|
||
summary: Update Self-Serve config
|
||
operationId: updateSelfServeConfig
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SelfServeConfig'
|
||
responses:
|
||
'200':
|
||
description: Self-serve configuration updated successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/SelfServeConfig'
|
||
|
||
/branding:
|
||
get:
|
||
tags:
|
||
- Branding
|
||
summary: List branding options
|
||
description: Retrieve a list of branding options or a specific branding option if ID is provided
|
||
operationId: listBrandingOptions
|
||
parameters:
|
||
- name: id
|
||
in: query
|
||
required: false
|
||
schema:
|
||
type: integer
|
||
- $ref: '#/components/parameters/PageParam'
|
||
- $ref: '#/components/parameters/PerPageParam'
|
||
responses:
|
||
'200':
|
||
description: Branding options retrieved successfully
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
post:
|
||
tags:
|
||
- Branding
|
||
summary: Add branding option
|
||
description: Create a new branding option
|
||
operationId: addBrandingOption
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [name, description, cvr]
|
||
properties:
|
||
name: {type: string}
|
||
description: {type: string}
|
||
cvr: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Branding option added successfully
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
put:
|
||
tags:
|
||
- Branding
|
||
summary: Edit branding option
|
||
description: Update an existing branding option
|
||
operationId: editBrandingOption
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id: {type: integer}
|
||
name: {type: string}
|
||
description: {type: string}
|
||
cvr: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Branding option updated successfully
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
|
||
/roles:
|
||
get:
|
||
tags:
|
||
- Roles
|
||
summary: List roles
|
||
operationId: listRoles
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Roles
|
||
summary: Add role
|
||
operationId: addRole
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [name]
|
||
properties:
|
||
name: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
put:
|
||
tags:
|
||
- Roles
|
||
summary: Edit role
|
||
operationId: editRole
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, name]
|
||
properties:
|
||
id: {type: integer}
|
||
name: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/roles/permissions:
|
||
post:
|
||
tags:
|
||
- Roles
|
||
summary: Add permission to role
|
||
operationId: addRolePermission
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [role_id, permission]
|
||
properties:
|
||
role_id: {type: integer}
|
||
permission: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
delete:
|
||
tags:
|
||
- Roles
|
||
summary: Remove permission from role
|
||
operationId: removeRolePermission
|
||
parameters:
|
||
- name: role_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
- name: permission
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/roles/clone:
|
||
post:
|
||
tags:
|
||
- Roles
|
||
summary: Clone role
|
||
operationId: cloneRole
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [role_id, name]
|
||
properties:
|
||
role_id: {type: integer}
|
||
name: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/washcertificates:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: List wash certificates
|
||
operationId: listWashCertificates
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/xlvask/services/usage/orders:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get XLVask usage orders
|
||
operationId: getXlvaskUsageOrders
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/modules/xlvask/services/usage/orders/fast-link:
|
||
get:
|
||
tags:
|
||
- Modules
|
||
summary: Get XLVask usage orders fast link
|
||
operationId: getXlvaskUsageOrdersFastLink
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/department:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: List departments (superuser)
|
||
operationId: listSuperuserDepartments
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/department/prices:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get department prices
|
||
operationId: getDepartmentPrices
|
||
parameters:
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Departments
|
||
summary: Set department price
|
||
operationId: setDepartmentPrice
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [department_id, product_id, price]
|
||
properties:
|
||
department_id: {type: integer}
|
||
product_id: {type: integer}
|
||
price: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/superuser/department/variables:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get department variables
|
||
operationId: getDepartmentVariables
|
||
parameters:
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Departments
|
||
summary: Set department variable
|
||
operationId: setDepartmentVariable
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [department_id, variable, value]
|
||
properties:
|
||
department_id: {type: integer}
|
||
variable: {type: string}
|
||
value: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/departments/daily-reports:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: List daily reports
|
||
operationId: listDailyReports
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
post:
|
||
tags:
|
||
- Departments
|
||
summary: Add daily report
|
||
operationId: addDailyReport
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [department_id, date, report]
|
||
properties:
|
||
department_id: {type: integer}
|
||
date: {type: string}
|
||
report: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
put:
|
||
tags:
|
||
- Departments
|
||
summary: Edit daily report
|
||
operationId: editDailyReport
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [id, report]
|
||
properties:
|
||
id: {type: integer}
|
||
report: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/departments/daily-reports/get:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get daily report
|
||
operationId: getDailyReport
|
||
parameters:
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
- name: date
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/departments/daily-reports/product-count:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get product count for daily reports
|
||
operationId: getDailyReportProductCount
|
||
parameters:
|
||
- name: date
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
- name: date_to
|
||
in: query
|
||
required: false
|
||
schema: {type: string}
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
- name: product_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/departments/daily-reports/transaction-count:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get transaction count for daily reports
|
||
operationId: getDailyReportTransactionCount
|
||
parameters:
|
||
- name: date
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
- name: date_to
|
||
in: query
|
||
required: false
|
||
schema: {type: string}
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
/departments/daily-reports/bookings-count:
|
||
get:
|
||
tags:
|
||
- Departments
|
||
summary: Get bookings count for daily reports
|
||
operationId: getDailyReportBookingsCount
|
||
parameters:
|
||
- name: date
|
||
in: query
|
||
required: true
|
||
schema: {type: string}
|
||
- name: department_id
|
||
in: query
|
||
required: true
|
||
schema: {type: integer}
|
||
responses:
|
||
'200':
|
||
description: Success
|
||
|
||
# Account Security - Passkeys
|
||
/account/security/passkeys:
|
||
get:
|
||
tags:
|
||
- Security
|
||
summary: List passkeys for the authenticated user
|
||
operationId: listPasskeys
|
||
responses:
|
||
'200':
|
||
description: A list of passkeys
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Passkey'
|
||
'400':
|
||
description: Invalid session or request
|
||
post:
|
||
tags:
|
||
- Security
|
||
summary: Create/add a passkey for the authenticated user
|
||
operationId: createPasskey
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PasskeyCreateRequest'
|
||
responses:
|
||
'200':
|
||
description: Passkey created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
'400':
|
||
description: Invalid session or request
|
||
|
||
/account/security/passkeys/{id}:
|
||
patch:
|
||
tags:
|
||
- Security
|
||
summary: Rename a passkey
|
||
operationId: renamePasskey
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/PasskeyRenameRequest'
|
||
responses:
|
||
'200':
|
||
description: Passkey renamed
|
||
'404':
|
||
description: Not found
|
||
delete:
|
||
tags:
|
||
- Security
|
||
summary: Delete a passkey
|
||
operationId: deletePasskey
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
responses:
|
||
'200':
|
||
description: Passkey deleted
|
||
'404':
|
||
description: Not found
|
||
|
||
components:
|
||
securitySchemes:
|
||
BearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
description: JWT token obtained from /auth/login or /auth/employee/login
|
||
|
||
parameters:
|
||
PageParam:
|
||
name: page
|
||
in: query
|
||
description: Page number for pagination
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
default: 1
|
||
PerPageParam:
|
||
name: per_page
|
||
in: query
|
||
description: Number of items per page
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 100
|
||
default: 30
|
||
SearchParam:
|
||
name: search
|
||
in: query
|
||
description: Search query string
|
||
schema:
|
||
type: string
|
||
LimitParam:
|
||
name: limit
|
||
in: query
|
||
description: Number of items per page
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 1000
|
||
default: 100
|
||
FiltersParam:
|
||
name: filters
|
||
in: query
|
||
description: Filters for the list (e.g., module:selfserve,status_code:200)
|
||
schema:
|
||
type: string
|
||
XCustomerNumber:
|
||
name: X-Customer-Number
|
||
in: header
|
||
required: false
|
||
description: |
|
||
Target customer number for subuser requests. Ignored for classic user sessions.
|
||
Required on customer-scoped endpoints when authenticated as a subuser unless
|
||
the target customer can be inferred from context.
|
||
schema:
|
||
type: integer
|
||
|
||
responses:
|
||
BadRequest:
|
||
description: Bad request - Invalid input parameters
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Error'
|
||
Unauthorized:
|
||
description: Unauthorized - Invalid or missing authentication token
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Error'
|
||
Forbidden:
|
||
description: Forbidden - Insufficient permissions
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Error'
|
||
NotFound:
|
||
description: Not found - Resource does not exist
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Error'
|
||
InternalServerError:
|
||
description: Internal server error
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Error'
|
||
|
||
schemas:
|
||
Error:
|
||
type: object
|
||
properties:
|
||
error:
|
||
type: string
|
||
description: Error message
|
||
code:
|
||
type: integer
|
||
description: HTTP status code
|
||
|
||
User:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: User ID
|
||
customer_number:
|
||
type: integer
|
||
description: e-conomic customer number
|
||
display_name:
|
||
type: string
|
||
description: User's display name
|
||
group_id:
|
||
type: integer
|
||
description: User group/role ID
|
||
phone_country_code:
|
||
type: integer
|
||
description: Phone country code
|
||
phone:
|
||
type: integer
|
||
description: Phone number
|
||
email:
|
||
type: string
|
||
format: email
|
||
description: Email address
|
||
sms_notifications_enabled:
|
||
type: boolean
|
||
description: SMS notifications enabled
|
||
email_notifications_enabled:
|
||
type: boolean
|
||
description: Email notifications enabled
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
SubuserGrant:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
billing_customer_number:
|
||
type: integer
|
||
description: e-conomic customer number
|
||
subuser:
|
||
type: integer
|
||
description: Subuser ID
|
||
enabled:
|
||
type: boolean
|
||
note:
|
||
type: string
|
||
nullable: true
|
||
permissions:
|
||
type: array
|
||
description: List of permission node keys
|
||
items:
|
||
type: string
|
||
example: BOOKINGS_LIST
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
deleted_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
|
||
SubuserGrantCreateRequest:
|
||
type: object
|
||
required:
|
||
- customer_number
|
||
- subuser_id
|
||
properties:
|
||
customer_number:
|
||
type: integer
|
||
description: e-conomic customer number
|
||
subuser_id:
|
||
type: integer
|
||
description: Subuser ID to grant permissions for
|
||
enabled:
|
||
type: boolean
|
||
default: true
|
||
note:
|
||
type: string
|
||
nullable: true
|
||
maxLength: 65535
|
||
permissions:
|
||
type: array
|
||
description: Optional list of permission keys; defaults will be applied if omitted
|
||
items:
|
||
type: string
|
||
|
||
SubuserGrantUpdateRequest:
|
||
type: object
|
||
properties:
|
||
enabled:
|
||
type: boolean
|
||
note:
|
||
type: string
|
||
nullable: true
|
||
maxLength: 65535
|
||
permissions:
|
||
type: array
|
||
items:
|
||
type: string
|
||
|
||
SubuserGrantSummary:
|
||
type: object
|
||
description: Summary of a subuser grant grouped by billing customer number
|
||
properties:
|
||
billing_customer_number:
|
||
type: integer
|
||
description: e-conomic customer number this grant applies to
|
||
permissions:
|
||
type: array
|
||
description: List of permission node keys enabled for this customer
|
||
items:
|
||
type: string
|
||
|
||
SubuserSelf:
|
||
type: object
|
||
description: Authenticated subuser profile with enabled grants
|
||
properties:
|
||
id:
|
||
type: integer
|
||
username:
|
||
type: string
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
email:
|
||
type: string
|
||
format: email
|
||
nullable: true
|
||
phone_country_code:
|
||
type: integer
|
||
nullable: true
|
||
phone:
|
||
type: integer
|
||
nullable: true
|
||
grants:
|
||
type: array
|
||
description: Enabled, non-deleted grants for the subuser grouped by billing customer number
|
||
items:
|
||
$ref: '#/components/schemas/SubuserGrantSummary'
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
suspended_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
|
||
PermissionNode:
|
||
type: object
|
||
properties:
|
||
key:
|
||
type: string
|
||
description: Permission node key
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
type:
|
||
type: string
|
||
description: Permission type (e.g., TOGGLE)
|
||
default:
|
||
type: boolean
|
||
|
||
PermissionNodeGroup:
|
||
type: object
|
||
properties:
|
||
group:
|
||
type: string
|
||
description:
|
||
type: string
|
||
nodes:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/PermissionNode'
|
||
|
||
UserCreate:
|
||
type: object
|
||
required:
|
||
- customer_number
|
||
- password
|
||
properties:
|
||
customer_number:
|
||
type: integer
|
||
password:
|
||
type: string
|
||
format: password
|
||
display_name:
|
||
type: string
|
||
group_id:
|
||
type: integer
|
||
email:
|
||
type: string
|
||
format: email
|
||
phone:
|
||
type: integer
|
||
phone_country_code:
|
||
type: integer
|
||
|
||
UserUpdate:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
customer_number:
|
||
type: integer
|
||
display_name:
|
||
type: string
|
||
group_id:
|
||
type: integer
|
||
email:
|
||
type: string
|
||
format: email
|
||
phone:
|
||
type: integer
|
||
phone_country_code:
|
||
type: integer
|
||
|
||
Order:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Order ID
|
||
customer_id:
|
||
type: integer
|
||
description: Customer number
|
||
customer_name:
|
||
type: string
|
||
description: Customer name
|
||
user_id:
|
||
type: integer
|
||
description: User ID
|
||
cashier_id:
|
||
type: integer
|
||
description: Cashier user ID
|
||
|
||
cashier_name:
|
||
type: string
|
||
description: Cashier name
|
||
department_id:
|
||
type: integer
|
||
description: Department ID
|
||
status:
|
||
type: string
|
||
description: Order status
|
||
total_net_amount:
|
||
type: number
|
||
format: float
|
||
description: Total order amount
|
||
po:
|
||
type: string
|
||
description: Purchase order number
|
||
nullable: true
|
||
lane:
|
||
type: string
|
||
description: Lane information
|
||
nullable: true
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
CollectedInvoiceEconomicCompareResponse:
|
||
type: object
|
||
description: Result of comparing a collected invoice with its E-conomic counterpart
|
||
properties:
|
||
collected_invoice_id:
|
||
type: integer
|
||
description: The internal collected invoice ID
|
||
example: 123
|
||
draft_id:
|
||
type: integer
|
||
nullable: true
|
||
description: E-conomic draft invoice ID, if present
|
||
example: 456
|
||
booked_id:
|
||
type: integer
|
||
nullable: true
|
||
description: E-conomic booked invoice ID, if present
|
||
example: 28368
|
||
warnings:
|
||
type: array
|
||
description: List of warnings detected during comparison
|
||
items:
|
||
type: string
|
||
example:
|
||
- "Total amount mismatch for draft invoice ID 456: E-Conomic total is 867.5, internal total is 694"
|
||
draft_total:
|
||
type: number
|
||
format: float
|
||
nullable: true
|
||
description: Total amount from the E-conomic draft (gross)
|
||
example: 867.5
|
||
booked_total:
|
||
type: number
|
||
format: float
|
||
nullable: true
|
||
description: Total amount from the E-conomic booked invoice (gross minus VAT if applicable)
|
||
example: 694
|
||
difference:
|
||
type: number
|
||
format: float
|
||
nullable: true
|
||
description: draft_total minus booked_total when both are available
|
||
example: 0
|
||
internal_total:
|
||
type: number
|
||
format: float
|
||
description: Internal total amount for the collected invoice
|
||
example: 694
|
||
order_ids:
|
||
type: array
|
||
description: List of order IDs included in the collected invoice
|
||
items:
|
||
type: integer
|
||
example: [38679, 39210]
|
||
required:
|
||
- collected_invoice_id
|
||
- internal_total
|
||
- order_ids
|
||
|
||
SelfServeLaneStatus:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Lane ID
|
||
status:
|
||
type: string
|
||
description: Current lane status (e.g., IDLE, OCCUPIED)
|
||
mode:
|
||
type: string
|
||
description: Current lane mode (e.g., AUTOMATIC, MANUAL)
|
||
state:
|
||
type: string
|
||
description: Current lane state (e.g., READY, WASHING)
|
||
wash_start_time:
|
||
type: integer
|
||
description: Timestamp when the wash started (0 if not washing)
|
||
nullable: true
|
||
elapsed_wash_time:
|
||
type: integer
|
||
description: Elapsed wash time in seconds
|
||
nullable: true
|
||
license_plate:
|
||
type: string
|
||
description: License plate of the vehicle in the lane
|
||
nullable: true
|
||
customer_number:
|
||
type: integer
|
||
description: Customer number associated with the current lane use
|
||
nullable: true
|
||
|
||
SelfServeConfig:
|
||
type: object
|
||
properties:
|
||
enabled:
|
||
type: boolean
|
||
description: Whether the self-serve module is enabled
|
||
minute_product:
|
||
type: integer
|
||
description: The product ID used for minute-based billing
|
||
|
||
SelfserveLaneService:
|
||
type: string
|
||
description: Allowed self-serve lane service name
|
||
enum:
|
||
- MACHINE
|
||
|
||
DepartmentSelfserveQuestion:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Question ID
|
||
department:
|
||
type: integer
|
||
description: Department ID
|
||
lane:
|
||
type: integer
|
||
description: Lane ID
|
||
product:
|
||
type: integer
|
||
description: Product ID
|
||
condition_id:
|
||
type: integer
|
||
description: Question condition object ID
|
||
nullable: true
|
||
question:
|
||
type: string
|
||
description: Question text
|
||
description:
|
||
type: string
|
||
description: Question description
|
||
order_priority:
|
||
type: integer
|
||
description: Display order priority (lower numbers shown first)
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
DepartmentSelfserveTask:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Task ID
|
||
department:
|
||
type: integer
|
||
description: Department ID
|
||
lane:
|
||
type: integer
|
||
description: Lane ID
|
||
product:
|
||
type: integer
|
||
description: Product ID
|
||
condition_id:
|
||
type: integer
|
||
description: Condition ID (if conditional task)
|
||
nullable: true
|
||
task:
|
||
type: string
|
||
description: Task text
|
||
description:
|
||
type: string
|
||
description: Task description
|
||
order_priority:
|
||
type: integer
|
||
description: Display order priority (lower numbers shown first)
|
||
services:
|
||
type: array
|
||
description: Services enabled by this task. Each item must be a valid service enum name.
|
||
items:
|
||
$ref: '#/components/schemas/SelfserveLaneService'
|
||
default: []
|
||
buttons:
|
||
type: array
|
||
description: Dynamic image button IDs enabled by this task.
|
||
items:
|
||
type: integer
|
||
default: []
|
||
dynamic_images_vehicle_type:
|
||
type: integer
|
||
nullable: true
|
||
description: Optional vehicle type selection override for the machine UI.
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
DepartmentSelfserveCondition:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Condition ID
|
||
department:
|
||
type: integer
|
||
description: Department ID
|
||
lane:
|
||
type: integer
|
||
description: Lane ID
|
||
product:
|
||
type: integer
|
||
description: Product ID
|
||
condition_id:
|
||
type: integer
|
||
description: Optional condition ID
|
||
nullable: true
|
||
name:
|
||
type: string
|
||
description: Condition name
|
||
description:
|
||
type: string
|
||
description: Condition description
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
DepartmentSelfserveConditionRule:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Rule ID
|
||
condition_id:
|
||
type: integer
|
||
description: Condition object ID
|
||
type:
|
||
type: string
|
||
description: Condition type (e.g., IS_TRUE, IS_FALSE)
|
||
object_type:
|
||
type: string
|
||
description: The object type to which the condition applies (e.g., question, task, etc.)
|
||
object_id:
|
||
type: integer
|
||
description: The object id to which the condition applies
|
||
name:
|
||
type: string
|
||
description: Condition name
|
||
description:
|
||
type: string
|
||
description: Condition description
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
DepartmentSelfserveVehicleCondition:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Vehicle condition ID
|
||
department:
|
||
type: integer
|
||
description: Department ID
|
||
lane:
|
||
type: integer
|
||
description: Lane ID
|
||
customer_id:
|
||
type: integer
|
||
description: Customer ID
|
||
nullable: true
|
||
reg:
|
||
type: string
|
||
description: Vehicle registration number
|
||
question:
|
||
type: integer
|
||
description: Question ID
|
||
value:
|
||
type: boolean
|
||
description: Answer value
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
deleted_at:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
|
||
OrderCreate:
|
||
type: object
|
||
required:
|
||
- customer_id
|
||
- department_id
|
||
properties:
|
||
customer_id:
|
||
type: integer
|
||
department_id:
|
||
type: integer
|
||
cashier_id:
|
||
type: integer
|
||
po:
|
||
type: string
|
||
lane:
|
||
type: string
|
||
|
||
OrderUpdate:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
customer_id:
|
||
type: integer
|
||
department_id:
|
||
type: integer
|
||
status:
|
||
type: string
|
||
po:
|
||
type: string
|
||
lane:
|
||
type: string
|
||
|
||
OrderItem:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
order_id:
|
||
type: integer
|
||
product_id:
|
||
type: integer
|
||
product_name:
|
||
type: string
|
||
quantity:
|
||
type: integer
|
||
unit_price:
|
||
type: number
|
||
format: float
|
||
discount:
|
||
type: number
|
||
format: float
|
||
total_price:
|
||
type: number
|
||
format: float
|
||
|
||
OrderItemCreate:
|
||
type: object
|
||
required:
|
||
- order_id
|
||
- product_id
|
||
- quantity
|
||
properties:
|
||
order_id:
|
||
type: integer
|
||
product_id:
|
||
type: integer
|
||
quantity:
|
||
type: integer
|
||
discount:
|
||
type: number
|
||
format: float
|
||
|
||
OrderItemUpdate:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
quantity:
|
||
type: integer
|
||
discount:
|
||
type: number
|
||
format: float
|
||
|
||
Department:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
economic_department_id:
|
||
type: integer
|
||
visible:
|
||
type: boolean
|
||
dimension:
|
||
type: integer
|
||
branding:
|
||
type: integer
|
||
longitude:
|
||
type: number
|
||
format: float
|
||
latitude:
|
||
type: number
|
||
format: float
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
DepartmentCreate:
|
||
type: object
|
||
required:
|
||
- name
|
||
- economic_department_id
|
||
properties:
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
economic_department_id:
|
||
type: integer
|
||
visible:
|
||
type: boolean
|
||
longitude:
|
||
type: number
|
||
format: float
|
||
latitude:
|
||
type: number
|
||
format: float
|
||
|
||
DepartmentUpdate:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
visible:
|
||
type: boolean
|
||
longitude:
|
||
type: number
|
||
format: float
|
||
latitude:
|
||
type: number
|
||
format: float
|
||
|
||
DepartmentLane:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
department:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
relay_in_id:
|
||
type: string
|
||
relay_out_id:
|
||
type: string
|
||
relay_machine_id:
|
||
type: string
|
||
dynamic_image_id:
|
||
type: integer
|
||
nullable: true
|
||
minimum: 1
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
DepartmentLaneCreate:
|
||
type: object
|
||
required:
|
||
- department
|
||
- name
|
||
properties:
|
||
department:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
relay_in_id:
|
||
type: string
|
||
relay_out_id:
|
||
type: string
|
||
relay_machine_id:
|
||
type: string
|
||
dynamic_image_id:
|
||
type: integer
|
||
nullable: true
|
||
minimum: 1
|
||
|
||
DepartmentLaneUpdate:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
department:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
relay_in_id:
|
||
type: string
|
||
relay_out_id:
|
||
type: string
|
||
relay_machine_id:
|
||
type: string
|
||
dynamic_image_id:
|
||
type: integer
|
||
nullable: true
|
||
minimum: 1
|
||
|
||
Product:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
price:
|
||
type: number
|
||
format: float
|
||
category_id:
|
||
type: integer
|
||
category_name:
|
||
type: string
|
||
visible:
|
||
type: boolean
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
ProductCreate:
|
||
type: object
|
||
required:
|
||
- name
|
||
- price
|
||
- category_id
|
||
properties:
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
price:
|
||
type: number
|
||
format: float
|
||
category_id:
|
||
type: integer
|
||
visible:
|
||
type: boolean
|
||
|
||
ProductUpdate:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
price:
|
||
type: number
|
||
format: float
|
||
category_id:
|
||
type: integer
|
||
visible:
|
||
type: boolean
|
||
|
||
Category:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
CategoryCreate:
|
||
type: object
|
||
required:
|
||
- name
|
||
properties:
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
|
||
CategoryUpdate:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
name:
|
||
type: string
|
||
description:
|
||
type: string
|
||
|
||
ModuleActionLog:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
description: Log ID
|
||
module:
|
||
type: string
|
||
description: The module name
|
||
action:
|
||
type: string
|
||
description: The action name
|
||
status_code:
|
||
type: integer
|
||
description: HTTP status code
|
||
data:
|
||
type: object
|
||
description: The action data (JSON decoded)
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
description: Log creation timestamp
|
||
|
||
Booking:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
customer_id:
|
||
type: integer
|
||
department_id:
|
||
type: integer
|
||
booking_time:
|
||
type: string
|
||
format: date-time
|
||
status:
|
||
type: string
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
BookingUpdate:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
type: integer
|
||
status:
|
||
type: string
|
||
booking_time:
|
||
type: string
|
||
format: date-time
|
||
|
||
Vehicle:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
user_id:
|
||
type: integer
|
||
description: Internal user ID owning the customer account
|
||
reg:
|
||
type: string
|
||
description: Vehicle registration number
|
||
customer_id:
|
||
type: integer
|
||
customer_name:
|
||
type: string
|
||
type:
|
||
type: integer
|
||
description: Product ID representing the vehicle wash type
|
||
reference:
|
||
type: string
|
||
nullable: true
|
||
description: Optional external reference/label
|
||
wash_subscription:
|
||
type: boolean
|
||
barred:
|
||
type: boolean
|
||
description: True if the associated customer is barred
|
||
addons:
|
||
type: object
|
||
properties:
|
||
enabled: { type: integer }
|
||
available: { type: integer }
|
||
list:
|
||
type: array
|
||
items:
|
||
type: object
|
||
last_order_id:
|
||
type: integer
|
||
nullable: true
|
||
xlvask:
|
||
type: object
|
||
nullable: true
|
||
description: XL Vask vehicle data when available
|
||
vehicle_types:
|
||
type: array
|
||
items:
|
||
type: object
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
Notification:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
user_id:
|
||
type: integer
|
||
title:
|
||
type: string
|
||
message:
|
||
type: string
|
||
read:
|
||
type: boolean
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
|
||
NotificationCreate:
|
||
type: object
|
||
required:
|
||
- user_id
|
||
- title
|
||
- message
|
||
properties:
|
||
user_id:
|
||
type: integer
|
||
title:
|
||
type: string
|
||
message:
|
||
type: string
|
||
|
||
Permission:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
description: Permission identifier
|
||
description:
|
||
type: string
|
||
description: Human-readable description
|
||
|
||
GoalsCriteria:
|
||
type: object
|
||
description: Goal evaluation criteria
|
||
properties:
|
||
type:
|
||
type: string
|
||
description: Criteria type (e.g., PRODUCT)
|
||
example: PRODUCT
|
||
target:
|
||
type: number
|
||
description: Target value for the goal
|
||
example: 100
|
||
label:
|
||
type: string
|
||
description: Optional short label/title for this goal criteria (max 255 characters)
|
||
example: Q1 Revenue Goal
|
||
start:
|
||
type: string
|
||
format: date-time
|
||
description: Start of the evaluation window (ISO 8601)
|
||
end:
|
||
type: string
|
||
format: date-time
|
||
description: End of the evaluation window (ISO 8601)
|
||
users:
|
||
type: array
|
||
description: List of user customer numbers included in the criteria
|
||
items: { type: integer }
|
||
departments:
|
||
type: array
|
||
description: List of department IDs included in the criteria
|
||
items: { type: integer }
|
||
products:
|
||
type: array
|
||
description: List of product IDs included in the criteria
|
||
items: { type: integer }
|
||
progress_alert_frequency:
|
||
type: string
|
||
description: |
|
||
Frequency of progress alerts for the goal.
|
||
Accepted values: DAILY, WEEKLY, MONTHLY, CHANGED, NONE.
|
||
The canonical field name is snake_case `progress_alert_frequency`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertFrequency` on input.
|
||
enum: [DAILY, WEEKLY, MONTHLY, CHANGED, NONE]
|
||
example: DAILY
|
||
progress_alert_destination:
|
||
type: string
|
||
description: |
|
||
Destination/channel where progress alerts should be delivered.
|
||
Accepted values: SLACK, EMAIL, SMS, NONE.
|
||
The canonical field name is snake_case `progress_alert_destination`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertDestination` on input.
|
||
enum: [SLACK, EMAIL, SMS, NONE]
|
||
example: NONE
|
||
progress_alert_progress_type:
|
||
type: string
|
||
description: |
|
||
What part of the progress should be included in alert messages.
|
||
Accepted values: ALL, PERCENTAGE_ONLY, COUNT_ONLY, COUNT_AND_TARGET, NONE.
|
||
The canonical field name is snake_case `progress_alert_progress_type`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertProgressType` on input.
|
||
enum: [ALL, PERCENTAGE_ONLY, COUNT_ONLY, COUNT_AND_TARGET, NONE]
|
||
example: ALL
|
||
progress_alert_style:
|
||
type: string
|
||
description: |
|
||
Presentation style of the alert.
|
||
Accepted values: DEPARTMENT_COMPARE, COLLECTIVE, SINGLE_DEPARTMENT, NONE.
|
||
The canonical field name is snake_case `progress_alert_style`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertStyle` on input.
|
||
enum: [DEPARTMENT_COMPARE, COLLECTIVE, SINGLE_DEPARTMENT, NONE]
|
||
example: NONE
|
||
progress_alert_format:
|
||
type: string
|
||
nullable: true
|
||
description: |
|
||
Optional custom template for the alert body. Supports tokens `{label}`, `{percent}`, `{count}`, `{target}`, `{timeframe}`, `{departments}`, `{prefix}`, `{body}`.
|
||
Max length depends on destination: 160 characters for SMS; 1024 characters for EMAIL/SLACK/other.
|
||
The canonical field name is snake_case `progress_alert_format`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertFormat` on input.
|
||
progress_alert_weekdays:
|
||
type: array
|
||
description: |
|
||
Weekdays on which progress alerts should be sent.
|
||
Use one or more of: MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY.
|
||
The canonical field name is snake_case `progress_alert_weekdays`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertWeekdays` on input.
|
||
items:
|
||
type: string
|
||
enum: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
|
||
example: [MONDAY, WEDNESDAY, FRIDAY]
|
||
progress_alert_time_of_day:
|
||
type: string
|
||
nullable: true
|
||
description: |
|
||
Time of day (with timezone) when progress alerts should be sent.
|
||
Format: `HH:MMZ` or `HH:MM±HH:MM` (24-hour clock with UTC offset). Examples: `14:30Z`, `09:15+02:00`, `18:45-05:00`.
|
||
The canonical field name is snake_case `progress_alert_time_of_day`.
|
||
For backward-compatibility the API also accepts camelCase `progressAlertTimeOfDay` on input.
|
||
pattern: '^([01]\d|2[0-3]):[0-5]\d(?:Z|[+-](?:[01]\d|2[0-3]):?[0-5]\d)$'
|
||
example: "14:30+02:00"
|
||
|
||
DepartmentGoal:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
created_by:
|
||
type: integer
|
||
description: ID of the user who created the goal
|
||
departments:
|
||
type: array
|
||
items: { type: integer }
|
||
criteria:
|
||
$ref: '#/components/schemas/GoalsCriteria'
|
||
created_at:
|
||
type: string
|
||
description: Creation timestamp
|
||
updated_at:
|
||
type: string
|
||
description: Update timestamp
|
||
|
||
DepartmentGoalCreate:
|
||
type: object
|
||
required: [departments, criteria]
|
||
properties:
|
||
departments:
|
||
type: array
|
||
items: { type: integer }
|
||
criteria:
|
||
$ref: '#/components/schemas/GoalsCriteria'
|
||
|
||
DepartmentGoalUpdate:
|
||
type: object
|
||
required: [id]
|
||
properties:
|
||
id:
|
||
type: integer
|
||
departments:
|
||
type: array
|
||
items: { type: integer }
|
||
criteria:
|
||
$ref: '#/components/schemas/GoalsCriteria'
|
||
Passkey:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
credential_id:
|
||
type: string
|
||
description: Base64URL-encoded credential ID
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
algorithm:
|
||
type: string
|
||
example: ES256
|
||
transports:
|
||
type: array
|
||
items:
|
||
type: string
|
||
example: ["usb", "nfc", "ble", "internal"]
|
||
sign_count:
|
||
type: integer
|
||
created_at:
|
||
type: string
|
||
format: date-time
|
||
updated_at:
|
||
type: string
|
||
format: date-time
|
||
PasskeyCreateRequest:
|
||
type: object
|
||
required: [credential_id, public_key, algorithm, transports]
|
||
properties:
|
||
credential_id:
|
||
type: string
|
||
description: Base64URL-encoded credential ID returned from WebAuthn
|
||
public_key:
|
||
type: string
|
||
description: Base64URL-encoded public key (COSE or PEM as stored)
|
||
algorithm:
|
||
type: string
|
||
example: ES256
|
||
transports:
|
||
type: array
|
||
items:
|
||
type: string
|
||
name:
|
||
type: string
|
||
nullable: true
|
||
PasskeyRenameRequest:
|
||
type: object
|
||
required: [name]
|
||
properties:
|
||
name:
|
||
type: string
|